| name | fallow |
| description | Codebase intelligence via fallow CLI — dead code, duplication, complexity, refactoring targets.
Load when investigating unused code, planning refactors, or reviewing fallow output.
|
Fallow
Fallow is a static analysis tool for TypeScript/JavaScript installed as a devDependency.
It finds unused code, duplication, complexity hotspots, and refactoring targets.
Run it via pnpm fallow scripts — never npx.
Quick reference
pnpm fallow
pnpm fallow:audit
pnpm fallow:health
pnpm fallow:dead-code
pnpm fallow:dupes
JSON output for programmatic use
Always use --format json --quiet 2>/dev/null and append || true.
Exit code 1 means "issues found" (normal), not a runtime error.
Only exit code 2 is a real error.
pnpm fallow dead-code --format json --quiet 2>/dev/null || true
pnpm fallow health --score --targets --format json --quiet 2>/dev/null || true
Useful flags
| Flag | Purpose |
|---|
--unused-exports | Filter to only unused exports |
--unused-files | Filter to only unused files |
--changed-since main | Only files changed since a ref |
--score | Show health score (0–100) |
--hotspots | Riskiest files by churn × complexity |
--targets | Ranked refactoring recommendations |
--mode semantic | Duplication: catch renamed-variable clones |
Configuration
Config lives at .fallowrc.json in the repo root.
This is a single package, so the config declares one entry point manually — the Pi extension entry ["src/index.ts"] — since fallow does not know that convention.
Rules use "error" (fail CI), "warn" (report only), or "off" (skip).
Suppressing findings
export const keepThis = 1;
export type KeepThisType = string;
The kind token must be the exact singular issue kind (unused-class-member, not unused-class-members) and the only text after the directive — fallow parses every space-separated token as a kind, so trailing prose (-- because …) produces "stale suppression" noise.
Put rationale on the line above the directive.
Use /** @public */ or /** @expected-unused */ JSDoc tags for library API exports.
Auto-fix cycle
Always dry-run first:
pnpm fallow fix --dry-run
pnpm fallow fix --yes
pnpm fallow dead-code
Key gotchas
- Fallow uses syntactic analysis only (no TypeScript compiler) — fully dynamic
import(variable) is not resolved.
- Re-export chains through barrel files are resolved correctly.
--changed-since is additive — only new issues in changed files.
- Never run
fallow watch — it is interactive and never exits.
- The human-readable
health --targets output omits the "Refactoring targets" section entirely when there are zero targets — to confirm a file dropped off the list, use --format json and check the targets array is empty rather than grepping the text output.
- Class-member liveness is keyed off
implements clauses: a member reached only through a structural type the class does not explicitly implements reads as dead once the last implements is removed.
Prefer re-declaring the genuine contract (implements ThatInterface) over a suppression.
If the consumer is wired via an object-literal property (which fallow cannot trace), prefer moving the read into a traced closure body at the composition root (e.g. getX: () => owner.member) over a suppression; suppress only when neither is practical.
- Duplication reports coordinates, not contents: when planning a dedup, read each clone group's exact line ranges before describing it.
The same byte-run is often an act + assertion sequence (the test subject — do not collapse it) rather than a fixture literal that can be extracted.