> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fallow.tools/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js bindings

> Call fallow analyses directly from Node.js via NAPI bindings. No CLI subprocess or JSON parsing, with the same JSON envelopes the CLI emits.

The `@fallow-cli/fallow-node` package exposes the main fallow analyses as async Node.js functions. The bindings avoid CLI subprocesses and JSON parsing, reuse the shared analysis layer, and return the same JSON report envelopes the CLI emits for `--format json`. The optional `detectSimilarCode` function verifies and launches its exact local model companion.

Use them when you want to embed fallow inside another tool, a Node.js server, an editor extension, or a custom script that otherwise would shell out to the CLI.

## Install

```bash theme={null}
npm install @fallow-cli/fallow-node
```

The package is a native NAPI-RS addon with platform-specific `optionalDependencies` for macOS (arm64, x64), Linux (gnu + musl on arm64 and x64), and Windows (x64, arm64). npm picks the matching binary at install time.

Node 18 or newer is required.

## Basic usage

```ts theme={null}
import {
  detectDeadCode,
  detectDuplication,
  detectSimilarCode,
  computeHealth,
} from '@fallow-cli/fallow-node';

const deadCode = await detectDeadCode({
  root: process.cwd(),
  explain: true,
});

console.log(deadCode.summary.total_issues);
console.log(deadCode.unused_exports);

const similar = await detectSimilarCode({
  root: process.cwd(),
  threshold: 0.8,
  top: 20,
});

console.log(similar.candidates);
```

Every function returns a promise resolving to the same JSON envelope the CLI emits when called with `--format json`: a top-level `kind` discriminator on typed roots, `schema_version`, `summary`, relative paths, injected `actions` arrays, and (when `explain: true`) a `_meta` block with docs links.

## API

All eight functions are async and accept an optional options object. Unknown fields are ignored. Enum-like fields take lowercase CLI-style literals (`"mild"`, `"cyclomatic"`, `"handle"`, `"low"`).

| Function                               | CLI equivalent                           | Returns                                                           |
| :------------------------------------- | :--------------------------------------- | :---------------------------------------------------------------- |
| `detectDeadCode(options?)`             | `fallow dead-code --format json`         | `DeadCodeReport`                                                  |
| `detectCircularDependencies(options?)` | `fallow dead-code --circular-deps`       | `DeadCodeReport` filtered to the `circular_dependencies` category |
| `detectBoundaryViolations(options?)`   | `fallow dead-code --boundary-violations` | `DeadCodeReport` filtered to the `boundary_violations` category   |
| `detectDuplication(options?)`          | `fallow dupes --format json`             | `DuplicationReport`                                               |
| `detectSimilarCode(options?)`          | `fallow similar-code --format json`      | `SimilarCodeReport` with unverified candidates                    |
| `detectFeatureFlags(options?)`         | `fallow flags --format json`             | `FeatureFlagsReport`                                              |
| `computeComplexity(options?)`          | `fallow health --format json`            | `HealthReport`                                                    |
| `computeHealth(options?)`              | `fallow health --format json`            | Alias for `computeComplexity` with a product-oriented name        |

### Shared options

Every options object extends `AnalysisOptions`:

| Field               | Type       | Default         | Purpose                                                                                          |
| :------------------ | :--------- | :-------------- | :----------------------------------------------------------------------------------------------- |
| `root`              | `string`   | `process.cwd()` | Project root directory                                                                           |
| `configPath`        | `string`   | auto-discover   | Path to `.fallowrc.json` / `.fallowrc.jsonc` / `fallow.toml` / `.fallow.toml`                    |
| `noCache`           | `boolean`  | `false`         | Skip the extraction cache                                                                        |
| `threads`           | `number`   | CPU count       | Parallelism; must be > 0                                                                         |
| `production`        | `boolean`  | `false`         | Production mode (excludes test/build files)                                                      |
| `changedSince`      | `string`   | unset           | Scope analysis to files changed since a git ref                                                  |
| `workspace`         | `string[]` | unset           | Restrict to named workspace packages (monorepo)                                                  |
| `changedWorkspaces` | `string`   | unset           | Restrict to workspaces whose files changed since a git ref. Mutually exclusive with `workspace`. |
| `explain`           | `boolean`  | `false`         | Inject a `_meta` block with metric / rule documentation                                          |

### Dead-code options

`detectDeadCode`, `detectCircularDependencies`, and `detectBoundaryViolations` accept the same superset, `DeadCodeOptions`. Setting any of the filter booleans below restricts the report to the selected issue types; leaving them all unset returns every category (the CLI's default behavior).

| Field                                                                            | Type       |                                                                      |
| :------------------------------------------------------------------------------- | :--------- | -------------------------------------------------------------------- |
| `unusedFiles` / `unusedExports` / `unusedDeps` / `unusedTypes`                   | `boolean`  |                                                                      |
| `unusedEnumMembers` / `unusedClassMembers`                                       | `boolean`  |                                                                      |
| `unresolvedImports` / `unlistedDeps`                                             | `boolean`  |                                                                      |
| `duplicateExports` / `circularDeps` / `boundaryViolations` / `staleSuppressions` | `boolean`  |                                                                      |
| `files`                                                                          | `string[]` | Restrict to specific files (like `fallow dead-code path/to/file.ts`) |
| `includeEntryExports`                                                            | `boolean`  | Report unused exports on entry files                                 |

### Duplication options

`DuplicationOptions` adds duplication-specific fields on top of `AnalysisOptions`:

| Field            | Type                                         | Default        |
| :--------------- | :------------------------------------------- | :------------- |
| `mode`           | `"strict" \| "mild" \| "weak" \| "semantic"` | `"mild"`       |
| `near`           | `boolean`                                    | `false`        |
| `minTokens`      | `number`                                     | `50`           |
| `minLines`       | `number`                                     | `5`            |
| `minOccurrences` | `number`                                     | `2`            |
| `threshold`      | `number`                                     | `0` (no limit) |
| `skipLocal`      | `boolean`                                    | `false`        |
| `crossLanguage`  | `boolean`                                    | `false`        |
| `ignoreImports`  | `boolean`                                    | `true`         |
| `top`            | `number`                                     | unset          |

Each returned clone group includes `spread`. Near-miss groups also include `similarity`. Duplication stats can include `clone_groups_ignored` and `near_candidates_skipped`; zero values are omitted.

### Similar-code options

`SimilarCodeOptions` adds model-backed discovery fields on top of
`AnalysisOptions`:

| Field       | Type                 | Default         |
| :---------- | :------------------- | :-------------- |
| `threshold` | `number` from 0 to 1 | config or `0.8` |
| `minLines`  | positive `number`    | config or `3`   |
| `top`       | positive `number`    | unset           |
| `files`     | `string[]`           | unset           |

The loader resolves the exact-version `fallow-similar-code` package and
verifies its native binary before source is read. `detectSimilarCode` never
downloads the model. After explicit user approval, run
`fallow similar-code setup --local` once through the CLI. Results remain
unverified. Read [Semantic similar code](/analysis/similar-code) before using a
score to plan a refactor.

### Feature flag options

`FeatureFlagsOptions` adds one field on top of `AnalysisOptions`:

| Field | Type     | Default |
| :---- | :------- | :------ |
| `top` | `number` | unset   |

### Complexity / health options

`ComplexityOptions` mirrors the `fallow health` flag surface:

| Field                                                                      | Type                                                      | Notes                                     |
| :------------------------------------------------------------------------- | :-------------------------------------------------------- | :---------------------------------------- |
| `maxCyclomatic`, `maxCognitive`                                            | `number` (0 to 65535)                                     | Per-function thresholds                   |
| `maxCrap`                                                                  | `number`                                                  | CRAP score ceiling                        |
| `top`                                                                      | `number`                                                  | Truncate rankings                         |
| `sort`                                                                     | `"cyclomatic" \| "cognitive" \| "lines" \| "severity"`    | Finding sort order (default `cyclomatic`) |
| `complexity`, `fileScores`, `coverageGaps`, `hotspots`, `targets`, `score` | `boolean`                                                 | Enable individual report sections         |
| `ownership`, `ownershipEmails`                                             | `boolean` + `"raw" \| "handle" \| "anonymized" \| "hash"` | Ownership-aware hotspots                  |
| `effort`                                                                   | `"low" \| "medium" \| "high"`                             | Filter refactoring targets                |
| `since`, `minCommits`                                                      | `string`, `number`                                        | Git history window for hotspots           |
| `coverage`, `coverageRoot`                                                 | `string`                                                  | Istanbul coverage file + root             |

## Structured errors

Rejected promises throw a `FallowNodeError` (a plain `Error` with extra fields) that mirrors the CLI's structured error surface:

```ts theme={null}
import type { FallowNodeError } from '@fallow-cli/fallow-node';

try {
  await detectDeadCode({ root: '/does/not/exist' });
} catch (err) {
  const e = err as FallowNodeError;
  console.error(e.name);      // "FallowNodeError"
  console.error(e.message);   // "analysis root does not exist: ..."
  console.error(e.exitCode);  // 2
  console.error(e.code);      // "FALLOW_INVALID_ROOT"
  console.error(e.context);   // "analysis.root"
  console.error(e.help);      // optional remediation hint
}
```

The exit-code ladder matches the CLI: `0` ok, `2` generic / validation, `7` network (paid features only), etc.

## When to use bindings vs the CLI

| Use the bindings                                                                  | Use the CLI                                                              |
| :-------------------------------------------------------------------------------- | :----------------------------------------------------------------------- |
| Embedding fallow in a long-running Node process (editor, devserver, CI runner)    | One-off invocation from a shell script or GitHub Action                  |
| You already have a Node runtime and want to skip subprocess + JSON parse overhead | You want zero runtime dependencies (native binary via `npx fallow`)      |
| You need to call many analyses in sequence without re-initializing                | You want CLI human output, progress bars, or interactive flags           |
| You need typed access to the result envelope in TypeScript                        | You consume the analysis from Rust, Python, Go, or any non-Node language |

Both paths run the same analysis engine and return the same data. The bindings are not a reduced subset.

## Limitations

* The bindings wrap the **one-shot** analyses. Commands that write to the filesystem (`fix`, `init`, `hooks install`, `hooks uninstall`, `audit --save-baseline`, `license activate`, `coverage setup`) are not exposed.
* `detectSimilarCode` is read-only and never performs its first model download. Use the CLI after explicit approval: `fallow similar-code setup --local`.
* No baseline or regression support yet. Use the CLI's `--baseline` / `--save-baseline` flags for those workflows.
* No watch mode. If you want incremental analysis, re-invoke the relevant function; fallow's per-file cache makes repeat runs fast.
* The API surface is young; breaking changes between minor versions are possible until it stabilizes.
