How to handle reported issues? A long list of reported issues with many false positives may be caused by several things. This document aims to help out with handling all of that.
- Unused files
- Unused dependencies
- Unlisted dependencies
- Unlisted binaries
- npx
- Unused exports
- Start using Knip in CI with lots of reported issues
Here are a few things to consider when Knip reports unused files:
-
Files may be reported as unused because they are not part of the dependency graph calculated from the (default)
entryfile patterns. When added to theentryfile patterns, they will no longer be reported as unused. -
Files may be reported as unused because existing plugins do not include that type of entry file yet. This usually happens when a tool or framework has its own locations regarding entry files. For example, Next.js has
pages/**/*.jsand Remix hasapp/routes/**/*.ts. Potential solutions:- Override plugin configuration to customize default patterns for existing plugins.
- Create a new plugin for tools or frameworks that are not in the list yet (or open an issue to request it).
- In the meantime, such file patterns can be added manually to the
entrypatterns of any workspace
-
When working in a repository that is not a package-based monorepo and contains many configuration files across the repository, see multi-project repositories to also match those files.
-
Files and/or directories should be ignored when they are not used by other source code and configuration files. Or when they are magically imported by other tooling, such as fixtures, mocks or templates. Here are a few examples of common ignore patterns:
{ "ignore": ["**/*.d.ts", "**/__mocks__", "**/__fixtures__"] } -
Source files are reported as unused, when only their build artifact is imported. For instance, a
src/module.tsfile is compiled todist/core.js. When another source file (or package) importsdist/core.js, thensrc/module.tsis not referenced from anywhere. The solution is to addsrc/module.tsto the entry file patterns. -
When a file in the dependency graph is ignored (caused by
.gitignore) and that is the only one that imports a source file, then the latter is reported as unused. For instance, for a dependency graph likesrc/index.ts→ignored/file.ts→src/module.ts, the ignored file is not part of the dependency graph and causessrc/module.tsto be reported as unused. In this case, potential solutions include:- Add
src/module.tsto theentryfile patterns. - Add
ignored/file.tsto theentryfile patterns. - Add
src/module.tsto theignorefile patterns. - Make sure
ignored/file.tsis not ignored by.gitignoreanymore. - Use
--no-gitignoreto ignore.gitignorefiles (soignored/file.tsis added to the dependency graph).
- Add
Dependencies imported in unused files are reported as unused dependencies. So it's good to remedy too many unused files first.
-
If unused dependencies are related to dependencies having a Knip plugin, the
configand/orentryfiles for that dependency may be at custom locations. The default values are in the plugin's documentation and can be overridden to match the custom path(s). -
If a dependency doesn't have a Knip plugin yet, this might result in false positives. For instance, when
tool.config.jsrefers to@tool/packagethen this dependency will be reported as an unused. Please file an issue or create a new plugin. -
Dependencies might be imported only from files with extensions like
.mdx,.vueor.svelte. See compilers for more details on how to include them. -
Problematic dependencies can be ignored:
{ "ignoreDependencies": ["ignore-me", "@problematic/package"] }
This means that a dependency is used, but not listed in package.json.
An unlisted dependency might be a transitive dependency that's imported directly. For instance, Knip uses fast-glob
which in turn has micromatch as a (transitive) dependency. Knip uses both fast-glob and micromatch, resulting in
micromatch being reported as unlisted. The solution is to make sure micromatch itself is also listed in
package.json.
Binaries are supposed to come from listed (dev) dependencies. Binaries not in the bin field of any those
package.json files will be reported as unlisted binaries, except for those listed as IGNORED_GLOBAL_BINARIES in
constants.ts.
Sometimes binaries are used like commitlint, but listed as @commitlint/cli in devDependencies. When the command
looks like npx commitlint or commitlint, @commitlint/cli might be reported as unused and commitlint as unlisted
(as it's technically a transitive dependency). This can usually be prevented by using the same package name in both
locations.
For npx scripts, Knip assumes that --yes (as in npx --yes package) means that the package is not listed. Knip
expects the dependency to be listed with --no or no flag at all.
The recommendation here is to be explicit: use --yes if the dependency is not supposed to be listed in package.json
(and vice versa).
Unused exports of entry files are not reported.
Sometimes exports of non-entry files are meant to be imported by consumers of the library. There are a few options to consider in this case:
- Move the export(s) to an entry file.
- Add the containing file to the
entryarray in the configuration. - Re-export the export(s) from an existing entry file.
- Mark the export(s) using the JSDoc
@publictag. - Ignore exports used in file.
Note that entries in the exports map in package.json are automatically added as entry files by Knip (except when
they are ignored by a .gitignore entry).
This type of QA only really works when it's tied to an automated workflow. But with too many issues to resolve in a large codebase this might not be feasible right away. Here are a few options that may help in the meantime:
- Use
--no-exit-codefor exit code0in CI. - Use
--include(or--exclude) output filters to report only the issue types that have little or no errors. - Use
rulesconfiguration to report only the issue types that have little or no errors. - Use separate Knip commands to analyze e.g. only
--dependenciesor--exports. - Use ignore patterns to filter out the most problematic areas.