Dead code 3 unused files, 12 unused exports, 2 unused deps 18ms
Duplication 4 clone groups (2.1% of codebase) 31ms
Complexity 7 functions exceed thresholds 4ms
Total 26 issues across 847 files 53ms
84 framework plugins. No Node.js runtime. No config file needed.
Install
Commands
Dead code
Finds unused files, exports, dependencies, types, enum members, class members, unresolved imports, unlisted dependencies, duplicate exports, circular dependencies, and type-only dependencies.
Duplication
Finds copy-pasted code blocks across your codebase. Suffix-array algorithm -- no quadratic pairwise comparison.
Four detection modes: strict (exact tokens), mild (default, AST-based), weak (different string literals), semantic (renamed variables and literals).
Complexity
Surfaces the most complex functions in your codebase and identifies where to spend refactoring effort.
CI integration
# GitHub Action
- uses: fallow-rs/fallow@v1
# Or run directly
- run: npx fallow --ci
--ci enables SARIF output, quiet mode, and non-zero exit on issues. Also supports:
--changed-since main-- analyze only files touched in a PR--baseline/--save-baseline-- fail only on new issues--format sarif-- upload to GitHub Code Scanning--format json/--format markdown-- for custom workflows Adopt incrementally -- surface issues without blocking CI, then promote when ready:
{ "rules": { "unused-files": "error", "unused-exports": "warn", "circular-dependencies": "off" } }
Configuration
Works out of the box. When you need to customize, create .fallowrc.json or run fallow init:
// .fallowrc.json
{
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
"entry": ["src/workers/*.ts", "scripts/*.ts"],
"ignorePatterns": ["**/*.generated.ts"],
"ignoreDependencies": ["autoprefixer"],
"rules": {
"unused-files": "error",
"unused-exports": "warn",
"unused-types": "off"
},
"health": {
"maxCyclomatic": 20,
"maxCognitive": 15
}
}
TOML also supported (fallow init --toml). Migrating from knip or jscpd? Run fallow migrate.
See the full configuration reference for all options.
Framework plugins
84 built-in plugins detect entry points and used exports for your framework automatically.
| Category | Plugins |
|---|---|
| Frameworks | Next.js, Nuxt, Remix, SvelteKit, Gatsby, Astro, Angular, NestJS, Expo, Electron, and more |
| Bundlers | Vite, Webpack, Rspack, Rsbuild, Rollup, Rolldown, Tsup, Tsdown, Parcel |
| Testing | Vitest, Jest, Playwright, Cypress, Storybook, Mocha, Ava |
| Databases | Prisma, Drizzle, Knex, TypeORM, Kysely |
| Monorepos | Turborepo, Nx, Changesets, Syncpack |
Full plugin list -- missing one? Add a custom plugin or open an issue.
Editor & AI support
- VS Code extension -- tree views, status bar, one-click fixes, auto-download LSP binary (Marketplace)
- LSP server -- real-time diagnostics, hover info, code actions, Code Lens with reference counts
- MCP server -- AI agent integration for Claude Code, Cursor, Windsurf (fallow-skills)
Performance
Benchmarked on real open-source projects (median of 5 runs, Apple M5).
Dead code: fallow vs knip
| Project | Files | fallow | knip v5 | knip v6 | vs v5 | vs v6 |
|---|---|---|---|---|---|---|
| zod | 174 | 19ms | 639ms | 334ms | 34x | 18x |
| fastify | 286 | 24ms | 1.13s | 289ms | 46x | 12x |
| 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 errors out on next.js. fallow completes in under 2 seconds.
Duplication: fallow vs jscpd
| Project | Files | fallow | jscpd | Speedup |
|---|---|---|---|---|
| fastify | 286 | 84ms | 2.83s | 34x |
| vue/core | 522 | 120ms | 3.13s | 26x |
| next.js | 20,416 | 3.16s | 24.64s | 8x |
No TypeScript compiler, no Node.js runtime. How it works | Reproduce benchmarks
Suppressing findings
// fallow-ignore-next-line unused-export
export const keepThis = 1;
// fallow-ignore-file
// Suppress all issues in this file
Also supports /** @public */ JSDoc tags for library exports consumed externally.
Limitations
fallow uses syntactic analysis -- no type information. This is what makes it fast, but type-level dead code is out of scope. Use inline suppression comments or ignoreExports for edge cases.
Documentation
- Getting started
- Configuration reference
- CI integration guide
- Migrating from knip
- Plugin authoring guide
Contributing
Missing a framework plugin? Found a false positive? Open an issue.
&&
License
MIT