Skip to content
Fallow home
All docs pages

Known limitations

Know where fallow can miss a finding or report a false positive, and how to work around it. Covers the limits of syntactic analysis, runtime patterns, and framework edge cases.

This page lists the patterns where fallow can miss a finding or report a false positive, with a workaround for each.

The default fallow analysis is syntactic. It does not use the TypeScript compiler or resolve types. The optional --type-aware pass adds limited checker evidence for the project questions that fallow answers. It does not make fallow a compiler or a general typed linter.

Each limitation below applies to a specific pattern. Most of them do not affect a standard TypeScript project with isolatedModules: true.

Syntactic analysis only (no TypeScript type information)

By default, fallow parses source code into syntax trees with Oxc, and uses oxc_semantic for scope-aware binding analysis. It does not run the TypeScript compiler or resolve type information, so the default path stays fast. Add --type-aware for exact symbol identity, private type leaks across files, targeted tests, and public type coupling.

Impact: Fallow handles type-only imports (import type { Foo }) correctly. It also tracks value imports that are used only as type annotations (e.g., import { Foo } followed by const x: Foo), with oxc_semantic reference counting. To detect conditional type exports or dead code behind generic interfaces, fallow needs real type resolution.

Workaround: Set isolatedModules: true in tsconfig.json. esbuild, swc, and Vite already require this setting, so most modern projects have it. With isolatedModules, every import is either an explicit import type or a real value import, so there is no ambiguity.

{
  "compilerOptions": {
    "isolatedModules": true
  }
}
Svelte export let prop ambiguity

In Svelte components, an export let declaration defines a component prop and a regular export. Fallow cannot tell props (which consumers use through the template) apart from utility exports that can really be unused.

Impact: Fallow can miss some unused exports in .svelte files.

Workaround: There is no configuration workaround. Review Svelte component exports manually. Move utility functions into separate .ts files, where fallow can track them accurately.

This limitation applies only to export let prop detection. Since v2.15.0, fallow does track imports that the template uses. It counts these as used:

  • Component tags.
  • Directives (use:tooltip, v-focus-trap).
  • Expressions.
  • $store subscriptions in Svelte.
  • v-on and v-bind object syntax in Vue.

File types has the details.

CSS and SCSS extraction

Fallow reads import directives and all SCSS syntax with regex extraction, not with a full parser. For CSS Module class names in standard CSS files, fallow uses a CSS parser (lightningcss). The parser does not read SCSS syntax, so .module.scss class names also come from regex extraction.

What's tracked:

  • @import and @use statements
  • @forward rules
  • @apply and @tailwind directives (as Tailwind dependency usage)
  • @plugin directives (Tailwind v4 plugin sources, package or relative)

What's not tracked:

  • composes: (CSS Modules composition). A class that another class composes can show as unused.
  • The scope of :global(). Fallow reads the class inside :global(.name) as a CSS Module class, so it can report a global class as unused.
  • Complex selector-based dependencies

Workaround: If fallow reports false positives for CSS files that use composes: or :global(), suppress them with ignorePatterns or inline comments.

{
  "ignorePatterns": ["**/legacy-styles/**/*.css"]
}
NestJS and dependency injection class members

Fallow tracks class member usage syntactically: it looks for direct references in source code. In NestJS and other DI frameworks, the DI container can call abstract class methods at runtime, with no direct reference in the source.

Impact: Fallow can report abstract class methods and properties that dependency injection uses as unused.

Workaround: In a project that uses DI a lot, disable unused-class-members:

{
  "rules": {
    "unused-class-members": "off"
  }
}
Library consumer types (noisy but correct)

If your package exports types for external consumers (e.g., ButtonProps, Config), fallow reports them as unused in your project. The finding is correct, because no internal file imports them.

Impact: Library authors get correct findings that add noise.

Workaround: Mark the public API files with ignoreExports:

{
  "ignoreExports": [
    { "file": "src/index.ts", "exports": ["*"] },
    { "file": "src/types.ts", "exports": ["*"] }
  ]
}
Config parsing ceiling

The built-in fallow plugins parse config files (e.g., vite.config.ts, jest.config.js) with the Oxc AST parser. The parser handles static objects, arrays, and defineConfig() wrappers, but it cannot evaluate arbitrary JavaScript.

What's handled:

  • Static object literals and arrays
  • defineConfig() / module.exports wrappers
  • String concatenation in simple cases

What's not handled:

  • Computed property keys
  • Conditional expressions (process.env.NODE_ENV === 'production' ? ... : ...)
  • Nested factory functions
  • Dynamic require() with variables

Workaround: Add the entry points that fallow misses to your fallow config manually:

{
  "entry": ["src/dynamic-entry.ts", "scripts/*.ts"]
}
React Native native modules

Fallow does not detect auto-linked React Native native packages (installed via npx pod-install or auto-linking) as used. These packages can have no explicit import in JavaScript code.

Impact: Fallow can report auto-linked packages such as react-native-screens or react-native-gesture-handler as unused dependencies.

Workaround: Add auto-linked packages to ignoreDependencies:

{
  "ignoreDependencies": [
    "react-native-screens",
    "react-native-gesture-handler",
    "react-native-safe-area-context"
  ]
}
Hidden directories are not traversed

Discovery skips directories whose names start with a dot. It traverses five conventional names by default (.storybook, .vitepress, .well-known, .changeset, .github). An active framework plugin can also add the hidden directory that its framework owns. A hidden directory that a package.json script names as a config or file argument (for example tsx ./.scripts/build.ts) is also traversed. Fallow drops every other hidden directory before it parses the contents. This keeps machine-written trees such as .next, .turbo, and .venv out of the analysis, with no configuration.

Impact: Fallow does not analyze first-party source in a hidden directory, for example agent hooks in .claude/hooks/ or plugins in .omp/extensions/. Fallow cannot see its imports and exports. The directory produces no findings of its own and does not mark the modules it imports as used.

Fallow reports the skip. For each hidden directory that holds source files your project did not exclude, it writes a skipped-source-dotdir entry in workspace_diagnostics[] and names the directory in one aggregated note on stderr.

Workaround: To add the directory to traversal, add a ! exception to ignorePatterns. Fallow then analyzes the files in the directory that the exception matches:

{
  "ignorePatterns": ["!.claude/**"]
}

Without an exception, a file, an export or a dependency that only the hidden directory uses can report as unused. To stop that false positive, add the file to entry, the export to ignoreExports or the dependency to ignoreDependencies:

{
  "entry": ["src/hook-helpers.ts"],
  "ignoreExports": [{ "file": "src/util.ts", "exports": ["helper"] }],
  "ignoreDependencies": ["zx"]
}

To analyze the hidden directory itself, point fallow at it. This run is separate and does not fix the findings of the main run:

fallow dead-code --root .claude

If the directory holds tool or agent scratch state that you never want analyzed, add it to ignorePatterns. The note then stops:

{
  "ignorePatterns": [".claude/**"]
}

Fallow does not report content that the run already excludes. A hidden directory that .gitignore covers (including a global gitignore, which often covers agent tooling) never produces the note.

See also