Skip to main content
fallow check performs dead code analysis on your JavaScript/TypeScript project. It builds a module graph from your entry points and reports anything that isn’t reachable. This analysis requires building and traversing a complete module graph. It can’t be approximated by reading files individually. Fallow does this deterministically in milliseconds, giving agents, developers, and CI pipelines the same reliable results.
fallow check

Issue types

Fallow detects 11 types of dead code:
Issue typeDescription
Unused filesFiles not reachable from any entry point
Unused exportsExported symbols never imported elsewhere
Unused typesType aliases and interfaces never referenced
Unused dependenciesPackages in dependencies never imported or used as script binaries
Unused devDependenciesPackages in devDependencies never imported or used as script binaries
Unused enum membersEnum values never referenced
Unused class membersClass methods and properties never referenced
Unresolved importsImport specifiers that cannot be resolved
Unlisted dependenciesImported packages missing from package.json
Duplicate exportsSame symbol exported from multiple modules
Circular dependenciesModules that import each other directly or transitively
Most projects find 50+ unused exports on first run. Start with --unused-exports for quick wins.
Here’s what typical output looks like when fallow finds multiple issue types:
$ fallow check
Unused files (16)
  src/server/jobs/worker.ts
  src/server/jobs/cron.ts
  src/features/savings/hooks/usePotGroups.ts
  src/features/tax/hooks/useKiaSuggestion.ts
  src/features/forecasting/hooks/useTargetProgress.ts
  ... and 11 more

Unused exports (20)
  src/components/Card/index.ts
    :1  CardFooter
  src/providers/trpc-provider/index.tsx
    :12 TRPCProvider
  src/server/jobs/queue.ts
    :61  enqueueJobDelayed
    :206 sweepStuckProcessingJobs

Unused type exports (314)
  ... across 87 files

Unused dependencies (1)
  @trpc/react-query

Duplicate exports (50)
  ... across 23 files

Found 401 issues in 0.16s

Filtering by issue type

Report only specific issue types:
fallow check --unused-files
fallow check --unused-exports --unused-types
fallow check --unresolved-imports --unlisted-deps

Output formats

Colored terminal output designed for readability.
fallow check --format human
src/components/Card/index.ts
  unused-export  CardFooter  (line 1)

src/server/jobs/queue.ts
  unused-export  enqueueJobDelayed  (line 61)
  unused-export  sweepStuckProcessingJobs  (line 206)

src/server/jobs/worker.ts
  unused-file  Not reachable from any entry point

Found 401 issues (17 errors, 384 warnings)

Incremental analysis

Only check files changed since a git ref:
fallow check --changed-since main
fallow check --changed-since HEAD~5
This is useful in CI to only report new issues in a pull request.
$ fallow check --changed-since main
Checking 12 changed files...

Unused exports (2)
  src/features/savings/hooks/usePotGroups.ts
    :8  usePotGroupTotals
  src/server/jobs/queue.ts
    :276 getDeadLetterJobs

Found 2 issues in 0.04s

Baseline comparison

Adopt fallow incrementally by saving a baseline of existing issues:
# Save current issues as baseline
fallow check --save-baseline

# Only fail on new issues (compared to baseline)
fallow check --baseline

Debugging

Trace why an export is or isn’t considered used:
fallow check --trace src/utils.ts:formatDate
fallow check --trace-file src/utils.ts
fallow check --trace-dependency lodash
Fallow uses syntactic analysis only: no TypeScript compiler, no type information. This is what makes it fast.
  1. Discovery: Walks your project, identifies entry points from package.json and framework plugins
  2. Parsing: Parallel parsing with Oxc and rayon, extracting imports and exports
  3. Resolution: Resolves import specifiers to file paths using oxc_resolver
  4. Graph: Builds a module graph with re-export chain propagation through barrel files
  5. Analysis: Walks the graph from entry points, reports unreachable code
This graph-based approach guarantees completeness regardless of project size.
Because fallow uses syntactic analysis only, it works best with projects using isolatedModules: true (required for esbuild, swc, and Vite). Legacy tsc-only projects may see some false positives on type-only imports.

Script binary analysis

Fallow parses package.json scripts to detect CLI tool usage, reducing false positives in unused dependency detection. When you have a script like "lint": "eslint src/", fallow recognizes that eslint is a binary provided by the eslint package and marks it as used. This works in several ways:
  • Binary name to package name mapping: Script commands like tsc, vitest, or next are mapped back to their parent packages (typescript, vitest, next). This prevents these packages from being reported as unused even when they’re never import-ed in source code.
  • --config arguments as entry points: When a script references a config file (e.g., jest --config jest.e2e.config.ts), fallow treats that config file as an entry point. This ensures config files are not flagged as unused.
  • File path arguments: Direct file references in scripts (e.g., node scripts/seed.js) are also recognized as entry points.
  • Env wrappers and package manager runners: Commands prefixed with cross-env, npx, pnpx, yarn dlx, or node -r are unwrapped to find the actual tool binary underneath.
{
  "scripts": {
    "build": "tsc && vite build",
    "test": "vitest --config vitest.config.ts",
    "lint": "cross-env NODE_ENV=production eslint src/"
  }
}
In this example, fallow detects typescript, vite, vitest, and eslint as used dependencies, and vitest.config.ts as an entry point.

Dynamic import resolution

Fallow resolves dynamic imports that use patterns rather than static strings. When you write import(\./locales/$.json`)`, the import target is not known at static analysis time. Fallow converts these patterns into glob expressions and matches them against discovered files. Supported patterns:
PatternExampleResolved as
Template literalsimport(`./icons/${name}.svg`)./icons/*.svg
String concatenationimport("./routes/" + path)./routes/*
import.meta.globimport.meta.glob("./modules/*.ts")./modules/*.ts
require.contextrequire.context("./themes", true, /\.css$/)./themes/**/*.css
Files matched by these glob patterns are marked as reachable in the module graph, preventing them from being reported as unused. This is useful for locale files, icon sets, route modules, and other convention-based directory structures.
Dynamic imports with fully runtime-computed paths (e.g., import(userInput)) cannot be resolved statically. Use entry in your config to mark those directories as entry points.

Re-export chain resolution

Barrel files (index.ts files that re-export from other modules) are common in JavaScript projects. Fallow fully resolves export * chains through multiple levels of barrel files with cycle detection.
// utils/math.ts
export const add = (a: number, b: number) => a + b;

// utils/index.ts (barrel)
export * from './math';

// src/index.ts (barrel)
export * from './utils';

// app.ts
import { add } from './src';
In this example, fallow traces the import of add in app.ts through src/index.ts and utils/index.ts back to utils/math.ts. The add export is correctly marked as used across the entire chain. This resolution handles:
  • Multi-level chains: Any depth of export * re-exports is followed until the original declaration is found.
  • Cycle detection: Circular re-export chains (e.g., a re-exports from b, b re-exports from a) are detected and handled without infinite loops.
  • Mixed re-exports: Named re-exports (export { foo } from './bar') and namespace re-exports (export * from './bar') are both tracked.

Cross-reference with duplication

When you run fallow check --include-dupes, fallow cross-references dead code findings with code duplication analysis. Clone instances that appear in unused files or overlap with unused exports are flagged as combined high-priority findings.
fallow check --include-dupes
Use --include-dupes to prioritize cleanup: if a block of code is both duplicated and unused, removing it eliminates dead code and reduces duplication at the same time. The cross-reference identifies:
  • Clone instances in unused files: If a file is unreachable from entry points and contains duplicated code, the duplication finding is elevated.
  • Clone instances overlapping unused exports: If an unused export contains code that is duplicated elsewhere, both findings are reported together.
Use --include-dupes in CI to catch the highest-impact cleanup opportunities first.

See also

CLI: check

Full reference for the fallow check command and its flags.

Rules & Severity

Control which issue types are errors, warnings, or disabled.

Auto-fix

Automatically remove the dead code fallow finds.