Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Find unused files, dependencies and exports in your TypeScript and JavaScript project
Knip is a tool for analyzing and managing unused files and dependencies in your JavaScript and TypeScript projects. It helps you keep your codebase clean and efficient by identifying and removing unnecessary code.
Identify Unused Files
This feature allows you to identify files in your project directory that are not being used. The code sample demonstrates how to use Knip to find unused files in the './src' directory.
const knip = require('knip');
knip.findUnusedFiles({
directory: './src'
}).then(unusedFiles => {
console.log('Unused files:', unusedFiles);
});
Identify Unused Dependencies
This feature helps you find dependencies listed in your package.json that are not being used in your project. The code sample shows how to use Knip to find unused dependencies in the current directory.
const knip = require('knip');
knip.findUnusedDependencies({
directory: './'
}).then(unusedDependencies => {
console.log('Unused dependencies:', unusedDependencies);
});
Remove Unused Files
This feature allows you to automatically remove files that are not being used in your project. The code sample demonstrates how to use Knip to remove unused files in the './src' directory.
const knip = require('knip');
knip.removeUnusedFiles({
directory: './src'
}).then(() => {
console.log('Unused files removed');
});
Remove Unused Dependencies
This feature helps you automatically remove dependencies that are not being used in your project. The code sample shows how to use Knip to remove unused dependencies in the current directory.
const knip = require('knip');
knip.removeUnusedDependencies({
directory: './'
}).then(() => {
console.log('Unused dependencies removed');
});
Depcheck is a tool that helps you find unused dependencies in your project. It analyzes your codebase to identify dependencies that are not being used. Compared to Knip, Depcheck focuses more on dependencies and does not provide functionality for identifying or removing unused files.
Unimported is a tool that helps you find and remove unused files and dependencies in your project. It provides similar functionality to Knip, including the ability to identify and remove unused files and dependencies. However, Unimported may have different configuration options and performance characteristics.
Madge is a tool for visualizing and analyzing the dependency graph of your project. It can help you identify circular dependencies and unused files. While Madge provides some overlapping functionality with Knip, it is more focused on visualizing dependencies and analyzing the structure of your codebase.
Knip finds unused files, dependencies and exports in your JavaScript and TypeScript projects. Less code leads to improved performance, less maintenance and easier refactorings.
export const myVar = true;
ESLint handles files in isolation, so the export
keyword "blocks" further analysis. Unused files and dependencies will
also not be detected. You could think of Knip as going (far!) beyond the no-unused-vars
rule of ESLint. Knip lints the
project as a whole (or parts of it).
It's only human to forget removing things that you no longer use. But how do you find out? Where to even start finding things that can be removed?
The dots don't connect themselves. This is where Knip comes in:
package.json
.tsconfig.json
, or TypeScript allowJs: true
).Knip really shines in larger projects. A little bit of configuration will pay off, I promise. A comparison with similar tools answers the question why another unused file/dependency/export finder?
Knip is a fresh take on keeping your projects clean & tidy!
“An orange cow with scissors, Van Gogh style” - generated with OpenAI
Please report any false positives by opening an issue in this repo. Bonus points for adding a public repository or
opening a pull request with a directory and example files in test/fixtures
. Correctness and bug fixes have priority
over new features:
export
keyword, uninstall unused dependencies, delete files (like --fix
of ESLint).npm install -D knip
Knip supports LTS versions of Node.js, and currently requires at least Node.js v16.17 or v18.6. Knip is cutting edge!
Create a configuration file, let's give it the default name knip.json
with these contents:
{
"entryFiles": ["src/index.ts"],
"projectFiles": ["src/**/*.ts"]
}
The entryFiles
target the starting point(s) to resolve code dependencies. The projectFiles
should contain all files
it should match them against, including potentially unused files.
Then run the checks:
npx knip
This will analyze the project and output unused files, exports, types and duplicate exports.
Knip works by creating two sets of files:
entryFiles
. In other words, the files that the entry files depend upon.projectFiles
.❯ npx knip
knip [options]
Options:
-c/--config [file] Configuration file path (default: ./knip.json, knip.jsonc or package.json#knip)
-t/--tsConfig [file] TypeScript configuration path (default: ./tsconfig.json)
--production Analyze only production source files (e.g. no tests, devDependencies, exported types)
--strict Consider only direct dependencies of workspaces. Not devDependencies, not ancestor workspaces.
--workspace Analyze a single workspace (default: analyze all configured workspaces)
--include Report only listed issue type(s), can be repeated
--exclude Exclude issue type(s) from report, can be repeated
--no-progress Don't show dynamic progress updates
--no-exit-code Always exit with code zero (0)
--max-issues Maximum number of issues before non-zero exit code (default: 0)
--reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
--reporter-options Pass extra options to the reporter (as JSON string, see example)
--debug Show debug output
--debug-level Set verbosity of debug output (default: 1, max: 3)
--performance Measure running time of expensive functions and display stats table
Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates
Examples:
$ knip
$ knip --production
$ knip --workspace packages/client --include files
$ knip -c ./knip.js --reporter compact
$ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
More info: https://github.com/webpro/knip
After analyzing all the files resolved from the entryFiles
against the projectFiles
, the report contains the
following types of issues:
files
- Unused files: did not find references to this filepackage.json
)
dependencies
- Unused dependencies: did not find references to this dependencyunlisted
- Unlisted dependencies: used dependencies, but not listed in package.json (1)exports
- Unused exports: did not find references to this exported variablensExports
- Unused exports in namespaces: did not find direct references to this exported variable (2)classMembers
- Unused class members: did not find references to this member of the exported classtypes
- Unused types: did not find references to this exported typensTypes
- Unused types in namespaces: did not find direct references to this exported variable (2)enumMembers
- Unused enum members: did not find references to this member of the exported enumduplicates
- Duplicate exports: the same thing is exported more than onceNotes:
unresolved/dir/module
mean?
node_modules/unresolved
package?paths
entry in tsconfig.json#compilerOptions
.You can --include
or --exclude
any of the types to slice & dice the report to your needs. Alternatively, they can be
added to the configuration (e.g. "exclude": ["dependencies"]
).
As always, make sure to backup files or use Git before deleting files or making changes. Run tests to verify results.
package.json
.package.json
.export
keyword in front of unused exports. Then you (or tools such as
TypeScript language services in VS Code and/or ESLint) can see whether the variable or type is used within the same
file. If this is not the case, it can be removed.🔁 Repeat the process to reveal new unused files and exports. Sometimes it's so liberating to remove things!
🚀 Knip finds issues of type files
, dependencies
, unlisted
and duplicates
very fast. Finding unused exports
requires deeper analysis (exports
, nsExports
, classMembers
, types
, nsTypes
, enumMembers
).
Use --include
to report only specific issue types (the following example commands do the same):
knip --include files --include dependencies
knip --include files,dependencies
Use --exclude
to ignore reports you're not interested in:
knip --include files --exclude classMembers,enumMembers
Use --performance
to see where most of the time is spent.
Workspaces and monorepos are handled out-of-the-box by Knip. Every workspace that is part of the Knip configuration will be part of the analysis. Here's a simple example:
{
"ignoreFiles": "**/fixtures/**",
"ignoreBinaries": ["deno", "git"],
"ignoreWorkspaces": ["packages/ignore-me"],
"workspaces": {
"packages/*": {
"entryFiles": "{index,cli}.ts!",
"projectFiles": "**/*.ts"
},
"packages/exception": {
"entryFiles": "something/different.js"
},
"not-a-workspace/in-package.json/but-has-package.json": {
"entryFiles": ["src/index.ts"],
"projectFiles": "src/**/*.ts"
}
}
}
All workspaces
or workspaces.packages
in package.json
with a match in workspaces
of Knip.json
are part of the
analysis.
Extra "workspaces" not cnfigured as a workspace in the root package.json
can be configured as well, Knip is happy to
analyze unused dependencies and exports from any directory with a package.json
.
Knip contains a growing list of plugins:
Plugins are automatically activated, no need to enable anything. Each plugin is automatically enabled based on simple
heuristics. Most of them check whether one or one of a few (dev) dependencies are listed in package.json
. Once
enabled, they add a set of configuration and/or entry files for Knip to analyze. These defaults can be overriden.
Most plugins use one or both of the following file types:
config
- custom dependency resolvers are applied to these filesentryFiles
- files to include with the analysis of the rest of the source codeMany configuration files use require
or import
statements to use dependencies, so they can be analyzed like the rest
of the source files. These configuration files are also entryFiles
.
Many plugins also include config
files. They are parsed by custom dependency resolvers.
eslint
plugin tells Knip that an "prettier"
entry in the array of plugins means that the
eslint-plugin-prettier
dependency should be installed.storybook
plugin understands that core.builder: 'webpack5'
in main.js
means that the
@storybook/builder-webpack5
and @storybook/manager-webpack5
dependencies are required.The only thing that a custom dependency resolver function does is return all referenced dependencies for the configuration files it is given.
Libraries and applications are identical when it comes to files and dependencies: whatever is unused should be removed.
Yet libraries usually have exports meant to be used by other libraries or applications. Such public variables and types
in libraries can be marked with the JSDoc @public
tag:
/**
* Merge two objects.
*
* @public
*/
export const merge = function () {};
Knip does not report public exports and types as unused.
The default mode for Knip is holistic and targets all project code. For instance test files usually import production files. This prevents the production files or its exports from being reported as unused, while both of them can be removed. This is why Knip has a production mode.
To analyze only production code, add an exclamation mark behind the patterns that are meant for production and use the
--production
flag to analyze (only) them. Here's an example:
{
"entryFiles": ["build/script.js", "src/index.ts!"],
"projectFiles": ["src/**/*.ts!"]
}
Configuration files, test files and build scripts should not be included. Knip looks for unused files, dependencies and export values in production code only.
Additionally, the --strict
flag can be used to:
dependencies
(not devDependencies
) when finding unused or unlisted dependencies.dependencies
(and not rely on packages of ancestor
workspaces).Plugins also have this distinction. For instance, Next.js entry files for pages (pages/**/*.tsx
) and Remix routes
(app/routes/**/*.tsx
) are production code, while Jest and Playwright entry files (e.g. *.spec.ts
) are not. All of
this is handled automatically by Knip and its plugins. You only need to point Knip to additional files or custom file
locations. The more plugins Knip will have, the more projects can be analyzed out of the box!
Knip provides the following built-in reporters:
json
symbol
(default)compact
codeowners
When the provided built-in reporters are not quite sufficient, a custom reporter can be implemented.
Pass --reporter ./my-reporter
, with the default export of that module having this interface:
type Reporter = (options: ReporterOptions) => void;
type ReporterOptions = {
report: Report;
issues: Issues;
cwd: string;
workingDir: string;
isProduction: boolean;
options: string;
};
The data can then be used to write issues to stdout
, a JSON or CSV file, or sent to a service, anything really!
The json
reporter output is meant to be consumed by other tools. It reports in JSON format as an array with one object
per file like this:
[
{
"file": "package.json",
"owners": ["@org/admin"],
"files": false,
"dependencies": ["jquery", "moment"],
"devDependencies": [],
"unlisted": [],
"exports": [],
"types": [],
"duplicates": []
},
{
"file": "src/Registration.tsx",
"owners": ["@org/owner"],
"files": true,
"dependencies": [],
"devDependencies": [],
"unlisted": ["react"],
"exports": ["lowercaseFirstLetter", "RegistrationBox"],
"types": ["RegistrationServices", "RegistrationAction"],
"duplicates": ["Registration", "default"]
}
]
The keys match the known issue types.
Use tools like miller or jtbl to consume the JSON and render a table in the terminal.
$ npx knip --reporter json | mlr --ijson --opprint --no-auto-flatten cat
file owners files unlisted exports types duplicates
src/Registration.tsx @org/owner true react lowercaseFirstLetter, RegistrationBox RegistrationServices, RegistrationAction Registration, default
src/ProductsList.tsx @org/team false - - ProductDetail -
$ npx knip --reporter json | mlr --ijson --omd --no-auto-flatten cat
| file | owners | files | duplicates |
| --- | --- | --- | --- |
| src/Registration.tsx | @org/owner | true | Registration, default |
| src/ProductsList.tsx | @org/team | false | |
Include specific issue types and/or replace the cat
command with put
for clean output:
npx knip --include files,duplicates --reporter json | mlr --ijson --opprint --no-auto-flatten put 'for (e in $*) { if(is_array($[e])) { $[e] = joinv($[e], ", ") } }'
npx knip --reporter json | mlr --ijson --omd --no-auto-flatten put 'for (e in $*) { if(is_array($[e])) { $[e] = joinv($[e], ", ") } }'
The default reporter shows the sorted symbols first:
$ knip
--- UNUSED FILES (2)
src/chat/helpers.ts
src/components/SideBar.tsx
--- UNUSED DEPENDENCIES (1)
moment
--- UNLISTED DEPENDENCIES (1)
react
--- UNUSED EXPORTS (5)
lowercaseFirstLetter src/common/src/string/index.ts
RegistrationBox src/components/Registration.tsx
clamp src/css.ts
restoreSession src/services/authentication.ts
PREFIX src/services/authentication.ts
--- UNUSED TYPES (4)
enum RegistrationServices src/components/Registration/registrationMachine.ts
type RegistrationAction src/components/Registration/registrationMachine.ts
type ComponentProps src/components/Registration.tsx
interface ProductDetail src/types/Product.ts
--- DUPLICATE EXPORTS (2)
Registration, default src/components/Registration.tsx
ProductsList, default src/components/Products.tsx
The compact reporter shows the sorted files first, and then a list of symbols:
$ knip --reporter compact
--- UNUSED FILES (2)
src/chat/helpers.ts
src/components/SideBar.tsx
--- UNUSED DEPENDENCIES (1)
moment
--- UNLISTED DEPENDENCIES (1)
react
--- UNUSED EXPORTS (4)
src/common/src/string/index.ts: lowercaseFirstLetter
src/components/Registration.tsx: RegistrationBox
src/css.ts: clamp
src/services/authentication.ts: restoreSession, PREFIX
--- UNUSED TYPES (3)
src/components/Registration/registrationMachine.ts: RegistrationServices, RegistrationAction
src/components/Registration.tsx: ComponentProps
src/types/Product.ts: ProductDetail
--- DUPLICATE EXPORTS (2)
src/components/Registration.tsx: Registration, default
src/components/Products.tsx: ProductsList, default
The codeowners
reporter is like compact
, but shows the sorted code owners (according to .github/CODEOWNERS
) first:
$ knip --reporter codeowners
--- UNUSED FILES (2)
@org/team src/chat/helpers.ts
@org/owner src/components/SideBar.tsx
--- UNUSED DEPENDENCIES (1)
@org/admin moment
--- UNLISTED DEPENDENCIES (1)
@org/owner src/components/Registration.tsx react
--- UNUSED EXPORTS (4)
@org/team src/common/src/string/index.ts: lowercaseFirstLetter
@org/owner src/components/Registration.tsx: RegistrationBox
@org/owner src/css.ts: clamp
@org/owner src/services/authentication.ts: restoreSession, PREFIX
--- UNUSED TYPES (3)
@org/owner src/components/Registration/registrationMachine.ts: RegistrationServices, RegistrationAction
@org/owner src/components/Registration.tsx: ComponentProps
@org/owner src/types/Product.ts: ProductDetail
--- DUPLICATE EXPORTS (2)
@org/owner src/components/Registration.tsx: Registration, default
@org/owner src/components/Products.tsx: ProductsList, default
The owner of package.json
is considered the owner of unused (dev) dependencies.
Use --reporter-options '{"path":".github/CODEOWNERS"}'
to pass another location for the code owners file.
There are already some great packages available if you want to find unused dependencies OR unused exports.
Although I love the Unix philosophy, here I believe it's efficient to handle multiple concerns in a single tool. When building a dependency graph of the project, an abstract syntax tree for each file, and traversing all of this, why not collect the various issues in one go?
This table is a work in progress, but here's a first impression. Based on their docs (please report any mistakes):
Feature | knip | depcheck | unimported | ts-unused-exports | ts-prune | find-unused-exports |
---|---|---|---|---|---|---|
Unused files | ✅ | - | ✅ | - | - | - |
Unused dependencies | ✅ | ✅ | ✅ | - | - | - |
Unlisted dependencies | ✅ | ✅ | ✅ | - | - | - |
Custom dependency resolvers | ✅ | ✅ | ❌ | - | - | - |
Unused exports | ✅ | - | - | ✅ | ✅ | ✅ |
Unused class members | ✅ | - | - | - | - | - |
Unused enum members | ✅ | - | - | - | - | - |
Duplicate exports | ✅ | - | - | ❌ | ❌ | ❌ |
Search namespaces | ✅ | - | - | ✅ | ❌ | ❌ |
Custom reporters | ✅ | - | - | - | - | - |
JavaScript support | ✅ | ✅ | ✅ | - | - | ✅ |
Configure entry files | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
Support monorepos | ✅ | - | - | - | - | - |
ESLint plugin available | - | - | - | ✅ | - | - |
✅ = Supported, ❌ = Not supported, - = Out of scope
TypeScript language services could play a major role in most of the "unused" areas, as they have an overview of the project as a whole. This powers things in VS Code like "Find references" or the "Module "./some" declares 'Thing' locally, but it is not exported" message. I think features like "duplicate exports" or "custom dependency resolvers" are userland territory, much like code linters.
Knip is Dutch for a "cut". A Dutch expression is "to be geknipt for something", which means to be perfectly suited for the job. I'm motivated to make knip perfectly suited for the job of cutting projects to perfection! ✂️
FAQs
Find unused files, dependencies and exports in your TypeScript and JavaScript projects
The npm package knip receives a total of 576,998 weekly downloads. As such, knip popularity was classified as popular.
We found that knip demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.