TL;DR: fallow is a Rust-native static analyzer for JS/TS codebases. It finds unused files, unused exports, unused dependencies, circular dependencies, and duplicated code. Zero config, 84 framework plugins auto-detected, sub-second on most projects. npx fallow check to try it now.
The problem that kept bugging me
Every codebase I've worked on has dead code. Exports that nothing imports. Dependencies in package.json that no file uses. Files that were "temporarily" left in after a refactor six months ago. Entire utility modules where 3 out of 12 functions are actually called.
That dead code isn't free. It bloats your bundle, slows your builds, and confuses anyone new to the project because they can't tell what's actually used and what's left over from two refactors ago. And the longer nobody touches it, the scarier it gets to delete.
This was annoying but manageable when humans wrote all the code. Now AI coding agents generate code at a pace where nobody can keep track of what's still needed. They create new files, refactor existing ones, but never go back to clean up what they left behind. They can't, really. Determining whether an export is unused requires building a complete module graph across every file in the project, which is a graph traversal problem, not a "read the file and figure it out" problem.
Existing tools work, but they were slow enough that I'd only run them occasionally. So I built fallow.
What it does
Fallow builds the full import/export graph of your project and reports:
- Unused files, exports, types, enum members, class members
- Unused dependencies and devDependencies
- Unresolved imports and unlisted dependencies
- Duplicate exports (same symbol from multiple modules)
- Circular dependencies
- Code duplication (4 detection modes)
12 issue types total. Here's what it looks like:
$ fallow check
● Unused files (16)
src/server/jobs/worker.ts
src/server/jobs/cron.ts
src/features/savings/hooks/usePotGroups.ts
... and 13 more
● Unused exports (20)
src/components/Card/index.ts
:1 CardFooter
src/providers/trpc-provider/index.tsx
:12 TRPCProvider
● Unused dependencies (1)
@trpc/react-query
● Duplicate exports (50)
... across 23 files
Found 401 issues in 0.16s
That last line is the part I'm most proud of. 0.16 seconds for 401 issues across a real-world codebase.
Why Rust
I didn't pick Rust to be trendy. The bottleneck in dead code analysis is parsing every file in the project to build the module graph. Fallow uses the Oxc parser natively in Rust (not through NAPI bindings) and rayon for parallel file processing across all cores. If you're already looking at oxlint or oxfmt, fallow is the same family. Oxlint replaces ESLint, oxfmt replaces Prettier, fallow finds what you're not using anymore.
Here's how that plays out against knip, the most popular JS/TS dead code analyzer:
| Project | Files | fallow | knip v5 | knip v6 | vs v5 | vs v6 |
|---|---|---|---|---|---|---|
| zod | 174 | 19ms | 639ms | 334ms | 34x | 18x |
| preact | 244 | 20ms | 819ms | — | 41x | — |
| fastify | 286 | 24ms | 1.13s | 289ms | 46x | 12x |
| vue/core | 522 | 63ms | 702ms | 299ms | 11x | 5x |
| TanStack/query | 901 | 148ms | 2.75s | 1.41s | 19x | 10x |
| svelte | 3,337 | 325ms | 1.93s | 860ms | 6x | 3x |
| next.js | 20,416 | 1.48s | —* | —* | — | — |
Knip v6 adopted the Oxc parser through NAPI bindings and got a lot faster. But it's still single-threaded and still runs in Node.js. The gap narrows on bigger projects, but fallow stays sub-second even at 3,000+ files. On the Next.js monorepo (20,416 files), the existing tooling just crashes without producing results. I keep going back to that repo to make sure fallow actually works on real projects, not just benchmarks that fit neatly in memory. *knip errors out on next.js without valid results.
Memory usage is 3-15x lower too, which matters if you're running this in CI.
Duplication detection built in
Most projects I've worked on also have a copy-paste problem. fallow has a dupes command that finds duplicated code blocks using a suffix array algorithm (no quadratic pairwise comparison):
$ fallow dupes
Clone group 1 (42 lines, 3 instances)
├─ src/features/forecasting/server/procedures/analytics.ts:141-181
├─ src/features/forecasting/server/procedures/cashflow.ts:153-194
└─ src/features/forecasting/server/procedures/income.ts:590-631
Duplication: 19.4% (27,255 duplicated lines across 398 files)
Found 1,184 clone groups, 2,959 instances (0.23s)
Four detection modes: strict (exact), mild (default), weak (different string literals), and semantic (catches renamed variables too). Clone families group related duplicates and suggest whether to extract a function or a module.
vs jscpd:
| Project | fallow | jscpd | Speedup |
|---|---|---|---|
| zod | 46ms | 909ms | 20x |
| preact | 44ms | 1.33s | 30x |
| fastify | 84ms | 2.83s | 34x |
| vue/core | 120ms | 3.13s | 26x |
| svelte | 400ms | 3.63s | 9x |
| next.js | 3.16s | 24.64s | 8x |
Zero config, 84 plugins
Fallow reads your package.json and auto-detects your framework stack. Next.js, Vite, Vitest, Playwright, Storybook, ESLint, Tailwind, Prisma, Drizzle, Turborepo, Nx... 84 plugins total, 31 of which do deep config file parsing (reading your next.config.js, vite.config.ts, etc. to understand entry points and aliases).
No .fallowrc.json required unless you want to customize. Just run it.
Auto-fix
Fallow can remove unused exports, unused dependencies, and unused enum members automatically:
# Preview what would change
fallow fix --dry-run
# Apply fixes
fallow fix
# Non-interactive for CI/agents
fallow fix --yes
It only touches things it's confident about. Unused files aren't auto-deleted because that's a bigger decision you should make yourself.
For the "I already use knip" crowd
Fair question. Knip is a solid tool with 141 plugins and a large community. If it's working for you and speed isn't a pain point, keep using it.
Reasons you might want fallow instead:
- Speed is a pain point (especially in CI or watch mode)
- You want dead code + duplication detection in one tool (replacing both knip and jscpd)
- You need SARIF output for GitHub Code Scanning
- You want
--changed-sinceto only check files modified in a PR - You want inline suppression comments (
// fallow-ignore-next-line) - You want baseline comparison for incremental adoption in existing projects
- You use AI coding agents and want structured JSON output or MCP integration
If you do switch, fallow migrate converts your knip config automatically.
AI agent integration
This is the use case I care about most. Agents generate code but have no way to know what's unused across the full project. Fallow gives them that:
# Agent checks its own work after generating code
fallow check --changed-since main --format json
# Agent auto-fixes what it can
fallow fix --yes --format json
There's also an MCP server (fallow-mcp) that exposes 6 tools for typed tool calling: analyze, check_changed, find_dupes, fix_preview, fix_apply, and project_info. Works with Claude Code, Cursor, and any MCP-compatible agent.
CI integration
# GitHub Actions
- uses: fallow-rs/fallow@v1
with:
format: sarif
SARIF output uploads to GitHub Code Scanning for inline PR annotations. --changed-since scopes analysis to PR changes only. --save-baseline and --baseline let you adopt incrementally without fixing every existing issue first.
Try it
npx fallow check
No install, no config, no signup. Takes about a second on most projects.
If you want duplication analysis too:
npx fallow dupes
- GitHub: fallow-rs/fallow
- Docs: docs.fallow.tools
- VS Code: fallow-rs.fallow-vscode
- MIT licensed
I'd love feedback. If fallow finds something useful (or misses something it shouldn't), open an issue or drop a comment here.
Top comments (0)