Fallow
Find unused code, code duplication, circular dependencies, and complexity hotspots in TypeScript/JavaScript projects
Install / Use
/learn @fallow-rs/FallowREADME
npx fallow
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
npx fallow # Run without installing
npm install -g fallow # Or install globally (macOS, Linux, Windows)
cargo install fallow-cli # Or via Cargo
Commands
fallow # Run all three analyses
fallow dead-code # Dead code only
fallow dupes # Duplication only
fallow health # Complexity only
fallow audit # Audit changed files (verdict: pass/warn/fail)
fallow fix --dry-run # Preview auto-removal of dead exports and deps
fallow watch # Re-analyze on file changes
Dead code
Finds unused files, exports, dependencies, types, enum members, class members, unresolved imports, unlisted dependencies, duplicate exports, circular dependencies (including cross-package cycles in monorepos), boundary violations, type-only dependencies, and test-only production dependencies. Entry points are auto-detected from package.json fields, framework conventions, and plugin patterns.
fallow dead-code # All dead code issues
fallow dead-code --unused-exports # Only unused exports
fallow dead-code --circular-deps # Only circular dependencies
fallow dead-code --boundary-violations # Only boundary violations
fallow dead-code --production # Exclude test/dev files
fallow dead-code --changed-since main # Only changed files (for PRs)
fallow dead-code --group-by owner # Group by CODEOWNERS for team triage
fallow dead-code --group-by directory # Group by first directory component
fallow dead-code --group-by package # Group by workspace package (monorepo)
Duplication
Finds copy-pasted code blocks across your codebase. Suffix-array algorithm -- no quadratic pairwise comparison.
fallow dupes # Default (mild mode)
fallow dupes --mode semantic # Catch clones with renamed variables
fallow dupes --skip-local # Only cross-directory duplicates
fallow dupes --trace src/utils.ts:42 # Show all clones of code at this location
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.
fallow health # Functions exceeding thresholds
fallow health --score # Project health score (0-100) with letter grade
fallow health --min-score 70 # CI gate: fail if score drops below 70
fallow health --top 20 # 20 most complex functions
fallow health --file-scores # Per-file maintainability index (0-100)
fallow health --hotspots # Riskiest files (git churn x complexity)
fallow health --targets # Ranked refactoring recommendations
fallow health --targets --effort low # Only quick-win refactoring targets
fallow health --trend # Compare against saved snapshot
fallow health --changed-since main # Only changed files
Audit
Quality gate for AI-generated code and PRs. Combines dead code + complexity + duplication scoped to changed files.
fallow audit # Auto-detects base branch
fallow audit --base main # Explicit base ref
fallow audit --base HEAD~3 # Audit last 3 commits
fallow audit --format json # Structured output with verdict
Returns a verdict: pass (exit 0), warn (exit 0, warn-severity only), or fail (exit 1). JSON output includes a verdict field for CI and agent integration.
CI integration
# GitHub Action
- uses: fallow-rs/fallow@v2
# GitLab CI — include the template and extend
include:
- remote: 'https://raw.githubusercontent.com/fallow-rs/fallow/main/ci/gitlab-ci.yml'
fallow:
extends: .fallow
# Or run directly on any CI
- run: npx fallow --ci
--ci enables SARIF output, quiet mode, and non-zero exit on issues. Also supports:
--group-by owner|directory|package-- group output by CODEOWNERS ownership, directory, or workspace package for team-level triage--summary-- show only category counts (no individual issues)--changed-since main-- analyze only files touched in a PR--baseline/--save-baseline-- fail only on new issues--fail-on-regression/--tolerance 2%-- fail only if issues grew beyond tolerance--format sarif-- upload to GitHub Code Scanning--format codeclimate-- GitLab Code Quality inline MR annotations--format annotations-- GitHub Actions inline PR annotations (no Action required)--format json/--format markdown-- for custom workflows (JSON includes machine-actionableactionsper issue)--format badge-- shields.io-compatible SVG health badge (fallow health --format badge > badge.svg)
Both the GitHub Action and GitLab CI template auto-detect your package manager (npm/pnpm/yarn) from lock files, so install/uninstall commands in review comments match your project.
Adopt incrementally -- surface issues without blocking CI, then promote when ready:
{ "rules": { "unused-files": "error", "unused-exports": "warn", "circular-dependencies": "off" } }
GitLab CI rich MR comments
The GitLab CI template can post rich comments directly on merge requests -- summary comments with collapsible sections and inline review discussions with suggestion blocks.
| Variable | Default | Description |
|---|---|---|
| FALLOW_COMMENT | "false" | Post a summary comment on the MR with collapsible sections per analysis |
| FALLOW_REVIEW | "false" | Post inline MR discussions at the relevant lines, with suggestion blocks for unused exports |
| FALLOW_MAX_COMMENTS | "50" | Maximum number of inline review comments |
In MR pipelines, --changed-since is set automatically to scope analysis to changed files. Previous fallow comments are cleaned up on re-runs.
The comment merging pipeline groups unused exports per file and deduplicates clone reports, keeping MR threads readable.
A GITLAB_TOKEN (PAT with api scope) is recommended for full features (suggestion blocks, cleanup of previous comments). CI_JOB_TOKEN works for posting but cannot delete comments from prior runs.
# .gitlab-ci.yml — full example with rich MR comments
include:
- remote: 'https://raw.githubusercontent.com/fallow-rs/fallow/main/ci/gitlab-ci.yml'
fallow:
extends: .fallow
variables:
FALLOW_COMMENT: "true" # Summary comment with collapsible sections
FALLOW_REVIEW: "true" # Inline discussions with suggestion blocks
FALLOW_MAX_COMMENTS: "30" # Cap inline comments (default: 50)
FALLOW_FAIL_ON_ISSUES: "true"
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
}
}
Architecture boundary presets enforce import rules between layers with zero manual config:
{ "boundaries": { "preset": "bulletproof" } } // or: layered, hexagonal, feature-sliced
Run fallow list --boundaries to inspect the expanded rules. TOML also supported (fallow init --toml). The init command auto-detects your project structure (monorepo layout, frameworks, existing config) and generates a tailored config. It also adds .fallow/ to your .gitignore (cache and local data). Scaffold a pre-commit hook with fallow init --hooks. Migrating
