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 and dependencies leads to improved performance, less maintenance and easier refactorings.
export const myVar = true;
ESLint handles files in isolation, so it does not know whether myVar
is actually used somewhere else. Knip lints the
project as a whole, and finds unused exports, files and dependencies
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 shines in both small and large projects. 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
When coming from version v0.13.3 or before, here are the breaking changes:
entryFiles
and projectFiles
options have been renamed to entry
and project
.--dev
argument and dev: true
option are gone, this is now the default mode (see production mode).workspaces
key (see workspaces).--dir
argument has been renamed to --workspace
.Please report any false positives by opening an issue in this repo. Bonus points for linking to a public repository
using Knip, or even opening a pull request with a directory and example files in test/fixtures
. Correctness and bug
fixes have priority over performance and new features.
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!
Knip has good defaults and you can run it without any configuration, but especially larger projects get more out of Knip
with a configuration file (or a knip
property in package.json
). Let's name this file knip.json
with these contents
(you might want to adjust right away for your project):
{
"$schema": "https://unpkg.com/knip@next/schema.json",
"entry": ["src/index.ts"],
"project": ["src/**/*.ts"]
}
The entry
files target the starting point(s) to resolve the rest of the imported code. The project
files should
contain all files to match against the files resolved from the entry files, including potentially unused files.
Then run the checks:
npx knip
This will analyze the project and output unused files, dependencies and exports.
$ npx knip --help
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 workspace (not devDependencies, not other workspaces)
--workspace Analyze a single workspace (default: analyze all configured workspaces)
--include-entry-exports Include unused exports in entry files (without `@public`)
--ignore Ignore files matching this glob pattern, can be repeated
--no-gitignore Don't use .gitignore
--include Report only provided issue type(s), can be comma-separated or repeated (1)
--exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
--no-progress Don't show dynamic progress updates
--reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
--reporter-options Pass extra options to the reporter (as JSON string, see example)
--no-exit-code Always exit with code zero (0)
--max-issues Maximum number of issues before non-zero exit code (default: 0)
--debug Show debug output
--debug-file-filter Filter for files in debug output (regex as string)
--performance Measure running time of expensive functions and display stats table
(1) Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates
Examples:
$ knip
$ knip --production
$ knip --workspace packages/client --include files,dependencies
$ knip -c ./config/knip.json --reporter compact
$ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
$ knip --debug --debug-file-filter '(specific|particular)-module'
More info: https://github.com/webpro/knip
Here's an example run using the default reporter:
This example shows more output related to unused and unlisted dependencies:
The report contains the following types of issues:
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"]
). 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
(1) This includes dependencies that could not be resolved. For instance, what does unresolved/dir/module
mean?
unresolved
package in node_modules/unresolved
.paths
entry in tsconfig.json#compilerOptions
.(2) The variable or type is not referenced directly, and has become a member of a namespace. That's why Knip is not sure whether this export can be removed, so please look into it.
This is the fun part! Knip, knip, knip ✂️
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 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!
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:
{
"ignore": "**/fixtures/**",
"ignoreBinaries": ["rm", "docker-compose"],
"ignoreWorkspaces": ["packages/ignore-me"],
"workspaces": {
"packages/*": {
"entry": "{index,cli}.ts!",
"project": "**/*.ts"
},
"packages/exception": {
"entry": "something/different.js"
},
"not-a-workspace/in-package.json/but-has-package.json": {
"entry": ["src/index.ts"],
"project": "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 configured 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
.
Here's a small output example when running Knip in a workspace:
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 the config filesentry
- files to include with the analysis of the rest of the source codeconfig
Plugins may include config
files. They are parsed by custom dependency resolvers. Here are some examples to get an
idea of how they work and why they are needed:
eslint
plugin tells Knip that the "prettier"
entry in the array of plugins
means that the
eslint-plugin-prettier
dependency should be installed. Or that the "airbnb"
entry in extends
requires the
eslint-config-airbnb
dependency.storybook
plugin understands that core.builder: 'webpack5'
in main.js
means that the
@storybook/builder-webpack5
and @storybook/manager-webpack5
dependencies are required.Custom dependency resolvers return all referenced dependencies for the configuration files it is given. Knip handles the rest to find which of those dependencies are unused or missing.
entry
Other 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 considered entry
files.
Getting false positives because a plugin is missing? Want to help out? Feel free to add your own plugin! Get started:
npm run create-plugin -- --name [myplugin]
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, including configuration files and tests. Test files usually import production files. This prevents the production files or its exports from being reported as unused, while sometimes both of them can be removed. This is why Knip has a "production mode".
To tell Knip what is production code, add an exclamation mark behind each pattern!
that is meant for production and
use the --production
flag. Here's an example:
{
"entry": ["src/index.ts!", "build/script.js"],
"project": ["src/**/*.ts!", "build/*.js"]
}
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:
codeowners
compact
json
symbol
(default)The compact
reporter shows the sorted files first, and then a list of symbols:
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.
Find more details and ideas in custom reporters.
There are already some great packages available if you want to find unused dependencies OR unused exports.
I love the Unix philosophy ("do one thing well"). But in this case 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 an ongoing comparison. 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 workspaces/monorepos | ✅ | ❌ | ❌ | - | - | - |
ESLint plugin available | - | - | - | ✅ | - | - |
✅ = Supported, ❌ = Not supported, - = Out of scope
WIP
The following commands are similar:
depcheck
knip --include dependencies,unlisted
The following commands are similar:
unimported
knip --production --include files,dependencies,unlisted
See production mode.
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.