Skip to content
Fallow home
All docs pages

Migrating from knip

Move from knip to fallow in minutes: one command converts your knip config. You also get duplication, complexity, and architecture boundary checks that knip does not have.

One command translates your knip configuration to fallow automatically. After the move, fallow also reports code duplication, complexity hotspots, maintainability scores, and architecture boundary violations. knip does not cover these.

Migration workflow

  1. Preview the migration

    Run fallow migrate --dry-run to see the generated config. The command writes no files.

    fallow migrate --dry-run

    fallow looks for knip.json, knip.jsonc, .knip.json, .knip.jsonc, knip.ts, knip.config.ts, and the knip field in package.json. Fallow detects the TypeScript config files (knip.ts, knip.config.ts) but cannot parse them. Convert them to knip.json first.

    {
      "$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
      // Migrated from knip.json
      "entry": [
        "src/index.ts",
        "src/cli.ts"
      ],
      "ignoreFindings": [
        "**/*.generated.ts"
      ],
      "ignoreDependencies": [
        "@types/node"
      ]
    }
    
    Migrated from: knip.json
    
    Warning (1):
      [knip] `ignoreBinaries`: Binary filtering is not configurable in fallow
    
    Note: knip and fallow use different glob engines; verify migrated entry /
    ignoreFindings with `fallow dead-code` before relying on CI.
    https://docs.fallow.tools/migration/from-knip
    
    Note: knip's ignore also suppresses dependency and manifest issues by file
    path; fallow's ignoreFindings never hides manifest-owned findings such as
    unused dependencies.
    https://docs.fallow.tools/migration/from-knip
  2. Generate the config

    When the preview looks correct, run the migration:

    fallow migrate            # Write .fallowrc.json
    fallow migrate --toml     # Or output as fallow.toml
  3. Review the config

    Open the generated config. Check the translated entry points, ignore patterns, and plugin mappings. Fallow shows a warning for each field that it could not migrate automatically.

  4. Run your first analysis

    Run the dead code analysis and compare the results with knip. Then try the analyses that knip does not have:

    fallow dead-code    # Unused code + circular deps + boundaries
    fallow dupes        # Code duplication
    fallow health       # Complexity hotspots + maintainability scores
    fallow              # All of the above in one pass

What gets migrated

knipFallow
entryentry
project-- (fallow auto-discovers project files)
ignoreignoreFindings (matching files stay in the analysis graph)
ignoreDependenciesignoreDependencies (a regex becomes a glob when a glob matches the same packages, see Warnings and caveats)
ignoreExportsUsedInFileignoreExportsUsedInFile (boolean and { type, interface } object form both supported)
rules, include, excluderules (knip issue types map to fallow rule names)
ignoreBinaries-- (not applicable)
Plugin configs-- (fallow's built-in plugins detect the framework; the migration warns you to remove the section)

Warnings and caveats

fallow migrate warns about each setting that it cannot translate, so you do not lose a setting without notice.

Unknown rule names. Your knip rules, exclude, or include entries can reference a key that fallow does not know. The cause can be a typo, a future knip rule, or an issue type that the migrator does not know yet. The migration then prints a warning like this one:

Warning (1):
  [knip] `rules.unsued-files`: unknown knip issue type `unsued-files`; not migrated (suggestion: check for a typo or report the missing mapping at https://docs.fallow.tools/migration/from-knip)

Some keys are on the documented list of keys that cannot be mapped: binaries, optionalPeerDependencies, and similar issue types that knip reports and fallow does not. For these keys, the warning reads issue type \X` has no fallow equivalent` and has no suggestion.

Glob-engine drift. knip and fallow use different glob engines. The migration copies entry and ignoreFindings verbatim, but they can match a slightly different set of files than in knip. When the migrated config has either field, the migrate command prints:

Note: knip and fallow use different glob engines; verify migrated entry /
ignoreFindings with `fallow dead-code` before relying on CI.
https://docs.fallow.tools/migration/from-knip

Common patterns (brace expansion {ts,tsx}, double-star **, src/**) match the same files in both engines. ignoreFindings keeps a leading ! as an exception to the earlier patterns. Run fallow dead-code on a representative subset before you use the migrated globs in CI.

Dependency regexes. knip reads an ignoreDependencies entry as a regex when it contains one of * + \ ( | { ^ $. Fallow reads ignoreDependencies entries as exact names or as globs, see ignoreDependencies. The migration converts a regex to a glob only when the glob matches exactly the same package names:

knip regexMigrated glob
@acme/.+ or ^@acme/.+$@acme/*
^@types/@types/*
^eslint-plugin-.*$eslint-plugin-*
-loader$*-loader
^react$react

A regex that has no exact glob form stays out of the config, for example an alternation such as ^(react|vue)$, a character class such as ^@acme/[a-z]+$, or .+ in the middle of a name. The migration prints a warning for each such entry:

Warning (1):
  [knip] `ignoreDependencies`: regex pattern `^(react|vue)$` skipped (no glob matches the same packages) (suggestion: rewrite it as a glob such as `@scope/*`, or add each dependency name)

Add the skipped entries by hand as globs or as exact names. After the migration, fallow dead-code names every ignoreDependencies glob that matches no declared dependency, so a glob with a typo does not go unnoticed. See Unmatched config patterns.

Ignore scope. knip's ignore also hides dependency and manifest issues by file path. Fallow's ignoreFindings never hides manifest-owned findings, such as unused dependencies. The migrate command prints a note about this difference for every knip migration.

Comparison

fallow is a standalone binary written in Rust. It needs no Node.js runtime, and has no JIT warmup and no garbage collection pauses.

The table shows cold runs (no cache) on real open-source projects (174 to 38,146 files). The fastest tool in each row is in bold.

ProjectFilesFallowknipFaster
zod17447ms279msFallow 5.9x
preact24474ms2.01sFallow 27.1x
fastify28664ms205msFallow 3.2x
vue/core522138mserrors*Fallow only
TanStack/query901560ms1.04sFallow 1.9x
vite1,420595mserrors*Fallow only
astro2,8593.76s1.21sknip 3.1x
svelte3,337611ms632msFallow 1.0x
next.js20,5582.95serrors*Fallow only
TypeScript38,1462.22s736msknip 3.0x

* Current knip (v5 and v6) exits without valid output on next.js, vite, and vue/core, because it fails to load the projects' own config files. Fallow analyzes them.

MetricFallowknip
Runtime dependencyNone (standalone binary)Node.js
CI setupDownload binaryInstall Node + npm dependencies

The knip numbers are for knip v6 (knip 6.6.1). Fallow is faster on the small and mid-size projects (fastify, preact, query, svelte, zod). Current knip is faster on astro and TypeScript. Fallow's advantage is that one tool does more, and it is not always faster at dead code analysis alone. It also analyzes the three projects that knip cannot load here. Against knip v5 (knip 5.87.0), fallow's lead is wider (for example 13.7x on fastify, 13.0x on zod, 10.3x on preact).

See also