Tracing export usage
Use--trace FILE:EXPORT to see the full usage chain for a specific export. Answers the question: “Who uses this export, and through which re-export paths?”
$ fallow dead-code --trace src/utils/format.ts:formatCurrency
formatCurrency, including indirect usage through barrel re-exports. Use this when:
- An export you expected to be used is reported as unused.
- You want to understand which consumers depend on a symbol before removing it.
- A re-export chain is not being resolved as expected.
Tracing file edges
Use--trace-file PATH to see all incoming and outgoing edges for a file in the module graph. Answers the question: “What does this file import, and what imports this file?”
- A file is reported as unused but you believe something should reference it.
- You want to verify that a file is reachable from entry points.
- You’re investigating why a file’s exports are all marked unused (maybe the file itself is unreachable).
Tracing dependency usage
Use--trace-dependency PACKAGE to find everywhere a package is used: imports, script binaries, and plugin detection. Answers the question: “Where is this dependency actually consumed?”
$ fallow dead-code --trace-dependency moment
package.json script binary usage, and plugin-based detection for the given package. Use this when:
- A dependency is reported as unused but you believe it’s used in scripts or config files.
- You want to audit which parts of your codebase depend on a specific package.
- You’re evaluating whether a dependency can be removed.
Tracing duplication clones
Usedupes --trace FILE:LINE to see all clone instances at a specific source location. Answers the question: “Where else does this duplicated code appear?”
- You want to find all copies of a duplicated block before refactoring.
- You’re deciding whether to extract a shared function or module.
- A duplication finding seems incorrect and you want to inspect the matched instances.
Performance profiling
Use--performance to get a timing breakdown of each pipeline stage. Answers the question: “Where is fallow spending time?”
$ fallow dead-code --performance
(other) row is the time inside TOTAL not attributed to a named stage (report assembly and inter-stage glue), so the sequential stages plus (other) sum to TOTAL. In combined mode (fallow with no subcommand) the duplication stage runs concurrently with the rest of the pipeline and is marked (concurrent); it is shown for reference but is not part of the TOTAL sum, so it can legitimately exceed TOTAL when duplication detection runs longer than the dead-code pass.
Use this when:
- Analysis is slower than expected and you want to find the bottleneck.
- You want to verify the cache is working (high hit rate means incremental runs are fast).
- You’re comparing performance across different configuration options.
Parallel parse timing
parse/extract runs across all cores. When the parse work was substantial and genuinely parallel, the line gains a (parallel: ~Nms CPU) suffix reporting the summed parse CPU across workers:
$ fallow dead-code --performance (cold cache)
fallow with no subcommand), the health breakdown reuses the discovered and parsed files from the dead-code pass, so its discover files and parse/extract rows read (measured above) and point you at the Pipeline Performance box where that cost is attributed.
In --format json, the timings carry parse_cpu_ms (summed parse CPU) alongside the wall-clock fields, and the health timings carry shared_parse. These are observational and vary run to run, so do not gate CI on them.
Cache behavior
Fallow caches parsed AST data using bincode serialization with xxh3 hashing. On later runs, unchanged files load from cache instead of being re-parsed.--no-cache when:
- You suspect stale cache entries are causing incorrect results.
- You’ve changed fallow versions and want a clean analysis.
- You’re benchmarking full parse performance.
--performance flag shows cache statistics, including how many files were cache hits vs. misses. A high hit rate on incremental runs is expected. Only modified files need re-parsing.
Common false positives
Dynamic imports with runtime values
Fallow resolves template literals andimport.meta.glob, but fully dynamic imports like import(variable) can’t be resolved statically.
Fix: Add the target directory to entry in your config:
Convention-based exports
Some frameworks consume exports by naming convention rather than explicit imports. For example, Next.jsgenerateStaticParams or Remix loader functions.
Fix: Fallow’s built-in plugins already handle most frameworks. If you’re using a niche framework, create a custom plugin or use ignoreExports:
Dependency injection frameworks
DI containers (NestJS, Angular, InversifyJS) resolve dependencies at runtime via decorators and metadata. Fallow skips decorated class members by default, but injected services may look unused if they’re only referenced via DI tokens. Fix: Add the DI-registered files as entry points, or suppress specific findings:@step, internal @measure, @log, etc.), opt them out of the skip via ignoreDecorators so methods carrying ONLY those names are checked for usage normally:
@step + @Inject keeps the conservative DI-friendly behavior.
Peer dependencies and optional dependencies
Packages listed inpeerDependencies or optionalDependencies are not analyzed by default since they may be provided by the consuming project.
Fix: If fallow incorrectly flags these, add them to ignoreDependencies:
Config files not recognized as entry points
If a config file (e.g.,tailwind.config.ts) is reported as unused, its framework plugin may not be active.
Fix: Run fallow list to check which plugins are active. If the relevant plugin isn’t detected, add the config file to entry:
See also
Dead Code Analysis
Overview of how fallow detects unused code.
CLI: dead-code
Full reference for the
fallow dead-code command and all its flags.Inline Suppression
Suppress individual findings with inline comments.