# Knip
> Knip finds and fixes unused dependencies, exports and files. Use it for
---
# Knip
Source: https://knip.dev/
Sponsor Me/Hire Me
Sponsored by:
Why use Knip?
Knip finds and fixes unused dependencies, exports and files. Use it for
enhanced code and dependency management.
How does it work?
Advanced analysis starting from fine-grained entry points based on the
actual frameworks and tooling in (mono)repos for accurate and actionable
results.
Battle-tested
Thousands of projects are already using Knip!
Knip comes with100+ pluginsfor tools and frameworks like Astro,
Cypress, ESLint, Jest, GitHub Actions, Next.js, Nx, Remix, Storybook,
Svelte, Vite, Vitest, Webpack and many, many more.
Try Knip on theplayground.
Troubleshooting
Need help?Start troubleshooting.
## Trusted by the world’s best software teams
## Introduction video
James Shoplandhas a great introduction and overview of Knip (thanks
James!):
## Created by awesome contributors
Special thanks to the wonderful people who have contributed to this project:
## Articles about Knip
A curated selection of articles about Knip, most recent first:
- Tom McWright:How to keep package.json under control(2025-09-11)
- Mohammed Farmaan:Declutter Your JavaScript and TypeScript Projects(2025-08-13)
- dip Engineer Blog:Knipで安心してデッドコードを撲滅する(2025-04-04/Japanese 🇯🇵)
- Tom MacWright:Knip: good software for cleaning up TypeScript tech debt(2024-10-25)
- Neng Apichet:มาทำความสะอาด Project โค้ดของเราด้วย Knip กัน(2024-10-22/Thai 🇹🇭)
- Anthony Pena:Knip: l’ultime outil pour faire le ménage dans vos
projets!(2024-10-08/French 🇫🇷)
- Taro:TypeScript/JavaScriptの不要なコードを削除するツール「Knip」の紹介(2024-07-25/Japanese 🇯🇵)
- Kevin Bailey:Delete Code with Knip(2025-10-31)
- Maddy Miller:Using Knip to find dead code in a high-traffic git repo(2023-09-17)
- Josh Goldberg:Speeding Up Centered Part 4: Unused Code Bloat(2023-08-21)
- Smashing Magazine:Knip: An Automated Tool For Finding Unused Files, Exports,
And Dependencies(2023-08-14)
- Effective TypeScript:Recommendation Update: ✂️ Use knip to detect dead code
and types(2023-07-29)
## Don’t just take our word for it
"Thanks Knip!"everyday,every team member,literally..knip.dev 🏅
2:34 PM · Jun 11, 2025
Thank you so much for this incredible piece of software! Knip is one of the most impressive tools I've seen in my career.
2:00 PM · Jun 5, 2025
Got my first plugin merged into Knip by @webpro.nl today! ☺️The contribution experience was fantastic: the docs were super clear, the code was straightforward to navigate, and the helper script to generate a new plugin got me 90% of the way there. Awesome. Thanks Lars!https://github.com/webpro-nl/knip/pull/1022
1:50 PM · Apr 10, 2025
All of the TanStack monorepos make use of knip.devIt's like eslint for detecting unused dependencies or even your own files/modules.
6:05 PM · Mar 25, 2025
The joy of adding knip.dev (by @webpro.nl) on a codebase! Right in time for spring cleaning 🧹🍃
8:32 PM · Mar 24, 2025
Knip helped us delete ~300k lines of unused code at Vercel.
6:40 AM · Jan 2, 2025
Knip may be the greatest tool ever conceived.https://www.npmjs.com/package/knip
7:57 PM · Oct 28, 2024
`knip` is the best code maintenance tool I've used in my 20 years of development, just an absolute work of art
5:33 PM · Jul 29, 2023
knip is great.A great example of stuff just working. It detects your environment so well and its defaults are almost too good because I didn’t realise it was doing everything automatically.
3:19 AM · Jul 4, 2024
Then was like “this is how tooling should be, this has taken me an hour not a day and it’s faster and more accurate and more future proof”Five stars ⭐️⭐️⭐️⭐️⭐️
12:20 PM · Jul 4, 2024
Crazy useful tool. Thought it would be a nightmare to setup in my Next.js+Workers repo but it has crazy good automatic detection for code dependencies. In short, Knip creates a graph of code use and highlights dead code for you to snip (knip).
12:35 PM · Jun 18, 2024
Lars is singlehandedly building the best tool to keep your code clean and your dependencies minimal. And he's so engaging and helpful. Can't imagine going back to not using knip 👏
9:55 AM · May 24, 2024
warning: do not use a tool like knip.dev + code search to delete a ton of unused code. It works too well.I just did this in https://github.com/sourcegraph/cody/pull/2705, and my boss said if I end the week with net negative lines of code committed, I'm in deep trouble.
1:55 AM · Jan 13, 2024
Ran knip.dev in @argos_ci, and boom 💥! Dead code detected instantly. With a good config, it can run on CI to keep projects clean. Installing this tool should be a no-brainer, like Prettier or ESLint.Kudos, @webprolific! 👏
11:00 AM · Nov 30, 2023
Problem:🚫 Your project has unused files.🚫 It has unused npm dependencies.🚫 It has unused TypeScript exports.But you haven't noticed, because these things are hard to spot.Solution: knipI just used knip to find and resolve dozens of issues.https://t.co/QmN3sNlmbm
2:44 PM · Aug 15, 2023
Knip helped me get rid of over 41k lines of code in legacy codebase 🥺🥺💕
4:51 PM · Nov 27, 2023
Big fans of Knip at @Contra. Such an extremely well developed and maintained project
3:18 PM · Nov 27, 2023
Just tried this onhttps://github.com/getsentry/sentry/- got some super useful results! Nice work.
7:03 PM · Nov 21, 2023
I've manage to delete 6k LOC in the last 30 minutes 🫣Great job here @webprolific 👍🏽
3:38 AM · Nov 21, 2023
knip is an amazing tool. Shoutout to @webprolific for building it 🙌.Not cleaning up correctly has a real maintenance cost. I've deleted lots of dead code - functions that were only used in tests and components that were only used in stories - all thanks to knip 🚀.
8:59 PM · Oct 16, 2023
🛠️ Knip👉🏻 Knip finds unused dependencies, exports and files in your JavaScript and TypeScript projects.👉🏻 Less code and dependencies lead to improved performance, less maintenance and easier refactorings.https://github.com/webpro-nl/knip
6:00 PM · Aug 28, 2023
Knip is wonderful at finding out unused code/dependencies in a legacy JavaScript/TypeScript applicationRecommend 💯Here's how Josh used it to remove code bloat in Centered:
11:13 AM · Aug 22, 2023
Unused files, exports, and dependencies often clutter projects, as it’s difficult knowing when one thing relies on another and scary to remove something you’re not sure is in use. 👀↬ Meet Knip, which scours projects for these unused artifacts:https://www.smashingmagazine.com/2023/08/knip-automated-tool-find-unused-files-exports-dependencies/
4:10 PM · Aug 14, 2023
Recommendation update: use knip to find dead code, types and dependencies in your @typescript ✂️https://effectivetypescript.com/2023/07/29/knip/
2:35 PM · Jul 29, 2023
This is worth checking out on GitHub. 👍https://github.com/webpro-nl/knip
7:29 AM · Oct 17, 2022
Streamlining React projects with Knip:Recently, I employed Knip for a project, and it worked wonders!It efficiently resolved issues with removing✅ Unused files,✅ Unused npm dependencies,✅ Unneeded TypeScript exports.A real time-saver for maintaining a clean and efficient codebase. 🛠️ #ReactDevelopmenthttps://t.co/IbJH2fIzsE
5:55 AM · Aug 21, 2023
Found a bunch of unused code, -dependencies, and unnecessary exports. Had just one false positive but overall pretty good. 10/10 would recommend.If you’ve got a JavaScript package/project use Knip and remove unnecessary code. ✂️
4:52 PM · Aug 19, 2023
## Read More
- Unused dependencies
- Unused exports
ISC License© 2024Lars Kappert
---
# Comparison & Migration
Source: https://knip.dev/explanations/comparison-and-migration
First of all, Knip owes a lot to the projects on this page and they’ve all been
inspirational in their own way. For best results, Knip hasa vision embracing
comprehensivenesswhich is larger in scope than any of the alternatives. So
if any of those tools has the right scope for your requirements, then by all
means, use what suits you best. Note that most projects are no longer
maintained.
All tools have in common that they have less features and don’t support the
concept ofmonorepos/workspaces. Feel free to send in projects that Knip
does not handle better, Knip loves to be challenged!
## Migration
A migration consists of deleting the dependency and its configuration file andgetting started with Knip. You should end up with less configuration.
## Comparison
### depcheck
Depcheckis a tool for analyzing the dependencies in a project to see:
how each dependency is used, which dependencies are useless, and which
dependencies are missing from package.json.
The project has plugins (specials), yet not as many as Knip has and they’re not
as advanced. It also supports compilers (parsers) for non-standard files.
The following commands are similar:
```typescript
depcheckknip--dependencies
```
### unimported
Find and fix dangling files and unused dependencies in your JavaScript
projects.
unimportedis fast and works well. It works in what Knip calls “production
mode” exclusively. If you’re fine with a little bit of configuration and don’t
want or need to deal with non-production items (such asdevDependenciesand
test files), then this might work well for you.
The following commands are similar:
```typescript
unimportedknip--production--dependencies--files
```
Project status: The project is archived and recommends Knip.
### ts-prune
Find unused exports in a typescript project. 🛀
ts-pruneaims to find potentially unused exports in your TypeScript project
with zero configuration.
The following commands are similar:
```typescript
ts-pruneknip--includeexports,types,nsExports,nsTypes
```
Useknip --exportsto also include class and enum members.
Project status: The project is archived and recommends Knip.
### ts-unused-exports
ts-unused-exportsfinds unused exported symbols in your Typescript
project
The following commands are similar:
```typescript
ts-unused-exportsknip--includeexports,types,nsExports,nsTypes
```
Useknip --exportsto also include class and enum members.
### tsr
Remove unused code from your TypeScript Project
tsr(previouslyts-remove-unused) removes unused exports, and works based
on a singletsconfig.jsonfile (includesandexcludes) and requires no
configuration. It removes theexportkeyword or the whole export declaration.
## Related projects
Additional alternative and related projects include:
- deadfile
- DepClean
- dependency-check
- find-unused-exports
- next-unused
- npm-check
- renoma
In general, thee18e.devwebsite and in particular theCleanupsection is a great resource when dealing with technical debt.
ISC License© 2024Lars Kappert
---
# Entry Files
Source: https://knip.dev/explanations/entry-files
Entry files are the starting point for Knip to determine what files are used in
the codebase. More entry files lead to increased coverage of the codebase. This
also leads to more dependencies to be discovered. This page explains how Knip
and its plugins try to find entry files so you don’t need to configure them
yourself.
## Default entry file patterns
For brevity, thedefault configurationon the previous page mentions onlyindex.jsandindex.ts, but the default set of file names and extensions is
actually a bit larger:
- index,mainandcli
- js,mjs,cjs,jsx,ts,mts,ctsandtsx
This means files likemain.cjsandsrc/cli.tsare automatically added as
entry files. Here’s the default configuration in full:
```typescript
{"entry":["{index,cli,main}.{js,cjs,mjs,jsx,ts,cts,mts,tsx}","src/{index,cli,main}.{js,cjs,mjs,jsx,ts,cts,mts,tsx}"],"project":["**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}!"]}
```
Next to the default locations, Knip looks forentryfiles in other places. In
a monorepo, this is done for each workspace separately.
The values you set override the default values, they are not merged.
Also seeFAQ: Where does Knip look for entry files?
## Plugins
Plugins often add entry files. For instance, if the Remix, Storybook and Vitest
plugins are enabled in your project, they’ll add additional entry files. Seethe next page about pluginsfor more details about this.
## Scripts in package.json
Thepackage.jsonis scanned for entry files. Themain,bin, andexportsfields may contain entry files. Thescriptsare also parsed to find entry
files and dependencies. SeeScript Parserfor more details.
## Ignored files
Knip respects.gitignorefiles. By default, ignored files are not added as
entry files. This behavior can be disabled by using the--no-gitignoreflag on the CLI.
## Configuring project files
Seeconfiguring project filesfor guidance on tuningentryandprojectand when to useignore.
ISC License© 2024Lars Kappert
---
# Plugins
Source: https://knip.dev/explanations/plugins
This page describes why Knip uses plugins and the difference betweenconfigandentryfiles.
Knip has an extensive and growinglist of built-in plugins. Feel free towrite a pluginso others can benefit too!
## What does a plugin do?
Plugins are enabled if the related package is listed in the list of dependencies
inpackage.json. For instance, ifastrois listed independenciesordevDependencies, then the Astro plugin is enabled. And this means that this
plugin will:
- Handleconfiguration fileslikeastro.config.mjs
- Addentry filessuch assrc/pages/**/*.astro
- Definecommand-line arguments
## Configuration files
Knip usesentry filesas starting points to scan your source code and
resolve other internal files and external dependencies. The module graph can be
statically resolved through therequireandimportstatements in those
source files. However, configuration files reference external dependencies in
various ways. Knip uses a plugin for each tool to parse configuration files and
find those dependencies.
### Example: ESLint
In the first example we look atthe ESLint plugin. The defaultconfigfile patterns include.eslintrc.json. Here’s a minimal example:
```typescript
{"extends":["airbnb","prettier"],"plugins":["@typescript-eslint"]}
```
Configuration files like this don’timportorrequireanything, but they do
require the referenced dependencies to be installed.
In this case, the plugin will return three dependencies:
- eslint-config-airbnb
- eslint-config-prettier
- @typescript-eslint/eslint-plugin
Knip will then look for missing dependencies inpackage.jsonand report those
as unlisted. And vice versa, if there are any ESLint plugins listed inpackage.json, but unused, those will be reported as well.
### Example: Vitest
The second example usesthe Vitest plugin. Here’s a minimal example of a
Vitest configuration file:
```typescript
import{ defineConfig }from'vitest/config';exportdefaultdefineConfig({test:{coverage:{provider:'istanbul',},environment:'happy-dom',},});
```
The Vitest plugin reads this configuration and returns two dependencies:
- @vitest/coverage-istanbul
- vitest-environment-happy-dom
Knip will look for missing and unused dependencies inpackage.jsonand report
accordingly.
Some tools allow configuration to be stored inpackage.json, that’s why some
plugins containpackage.jsonin the list ofconfigfiles.
Plugins parseconfigfiles to find external dependencies. Knip uses this to
determine unused and unlisted dependencies.
## Entry files
Many plugins have defaultentryfiles configured. When the plugin is enabled,
Knip will add entry files as configured by the plugin to resolve used files and
dependencies.
For example, ifnextis listed as a dependency inpackage.json, the Next.js
plugin will automatically add multiple patterns as entry files, such aspages/**/*.{js,jsx,ts,tsx}. Ifvitestis listed, the Vitest plugin adds**/*.{test,test-d,spec}.tsas entry file patterns. Most plugins have entry
files configured, so you don’t have to.
It’s mostly plugins for meta frameworks and test runners that haveentryfiles
configured.
Plugins result in less configuration
Plugins uses entry file patterns as defined in your configuration file of these
tools. So you don’t need to repeat this in your Knip configuration.
For example, let’s say your Playwright configuration contains the following:
```typescript
importtype{ PlaywrightTestConfig }from'@playwright/test';constconfig:PlaywrightTestConfig={testDir:'integration',testMatch:['**/*-test.ts'],};exportdefaultconfig;
```
The Playwright plugin will read this configuration file and return those entry
patterns (integration/**/*-test.ts). Knip will then not use the default entry
patterns.
You can still override this behavior in your Knip configuration:
```typescript
{"playwright":{"entry":"src/**/*.integration.ts"}}
```
This should not be necessary though. Please consider opening a pull request or a
bug report if any plugin is not behaving as expected.
Plugins try hard to automatically add the correct entry files.
## Entry files from config files
Entry files are part of plugin configuration (as described in the previous
section). Yet plugins can also return additional entry files after parsing
configuration files. Below are some examples of configuration files parsed by
plugins to return additional entry files. The goal of these examples is to give
you an idea about the various ways Knip and its plugins try to find entry files
so you don’t need to configure them yourself.
### Angular
The Angular plugin parses the Angular configuration file. Here’s a fragment:
```typescript
{"$schema":"./node_modules/@angular/cli/lib/config/schema.json","projects":{"knip-angular-example":{"architect":{"build":{"builder":"@angular-devkit/build-angular:browser","options":{"outputPath":"dist/knip-angular-example","main":"src/main.ts","tsConfig":"tsconfig.app.json"}}}}}}
```
This will result insrc/main.tsbeing added as an entry file (and@angular-devkit/build-angularas a referenced dependency).
Additionally, the Angular plugin returnstsconfig.app.jsonas a configuration
file for the TypeScript plugin.
### GitHub Actions
This plugin parses workflow YAML files. This fragment contains threerunscripts:
```typescript
jobs:integration:runs-on:ubuntu-lateststeps:-run:npm install-run:node scripts/build.js-run:node --loader tsx scripts/deploy.ts-run:playwright test -c playwright.web.config.tsworking-dir:e2e
```
From these scripts, thescripts/build.jsandscripts/deploy.tsfiles will be
added as entry files by the GitHub Actions plugin.
Additionally, the filee2e/playwright.web.config.tsis detected and will be
handed over as a Playwright configuration file.
Read more about this incommand-line arguments.
### webpack
Let’s take a look at this example webpack configuration file:
```typescript
module.exports=env=>{return{entry:{main:'./src/app.ts',vendor:'./src/vendor.ts',},module:{rules:[{test:/\.(woff|ttf|ico|woff2|jpg|jpeg|png|webp)$/i,use:'base64-inline-loader',},],},};};
```
The webpack plugin will parse this and add./src/app.tsand./src/vendor.tsas entry files. It will also addbase64-inline-loaderas a referenced
dependency.
In your config files, plugins can find additional entry files and also other
config files recursively.
## Bringing it all together
Sometimes a configuration file is a JavaScript or TypeScript file that imports
dependencies, but also contains configuration that needs to be parsed by a
plugin to find additional dependencies.
Let’s take a look at this example Vite configuration file:
```typescript
import{ defineConfig }from'vite';importreactfrom'@vitejs/plugin-react';exportdefaultdefineConfig(async({ mode,command })=>{return{plugins:[react()],test:{setupFiles:['./setup-tests.ts'],environment:'happy-dom',coverage:{provider:'c8',},},};});
```
This file importsviteand@vitejs/plugin-reactdirectly, but also
indirectly references thehappy-domand@vitest/coverage-c8packages.
The Vite plugin of Knip willdynamicallyload this configuration file and
parse the exported configuration. But it’s not aware of theviteand@vitejs/plugin-reactimports. This is why suchconfigfiles are also
automatically added asentryfiles for Knip tostaticallyresolve theimportandrequirestatements.
Additionally,./setup-tests.tswill be added as anentryfile.
When plugins dynamically load configuration files, conditional dependencies may
not be detected if the condition evaluates differently during analysis. Seeconditional or dynamic dependenciesfor details and workarounds.
## Command-Line Arguments
Plugins may define the arguments where Knip should look for entry files,
configuration files and dependencies. We’ve already seen some examples above:
```typescript
node--loadertsxscripts/deploy.tsplaywrighttest-cplaywright.web.config.ts
```
Please seescript parserfor more details.
## Summary
Plugins are configured with two distinct types of files:
- configfiles are dynamically loaded and parsed by the plugin
- entryfiles are added to the module graph
- Both can recursively lead to additional entry files, config files and
dependencies
ISC License© 2024Lars Kappert
---
# Why use Knip?
Source: https://knip.dev/explanations/why-use-knip
The value of removing clutter is clear, but finding it manually is tedious. This
is where Knip comes in: comprehensive and accurate results at any scale.
Knip finds and fixes unused dependencies, exports and files.
Deep analysis fromfine-grained entry pointsbased on the actual frameworks
and tooling in(mono)reposfor accurate and actionable results. Advanced
features for maximum coverage:
- Custom module resolution
- Configuration file parsers
- Advanced shell script parser
- Built-in and custom compilers
- Auto-fix most issues
## Less is more
There are plenty of reasons to delete unused files, dependencies and “dead
code”:
- Easier maintenance: things are easier to manage when there’s less of it.
- Improved performance: startup time, build time and/or bundle size can be
negatively impacted when unused code, files and/or dependencies are included.
Relying on tree-shaking when bundling code helps, but it’s not a silver
bullet.
- Easier onboarding: there should be no doubts about whether files, dependencies
and exports are actually in use or not. Especially for people new to the
project and/or taking over responsibilities this is harder to grasp.
- Prevent regressions: tools like TypeScript, ESLint and Prettier do all sorts
of checks and linting to report violations and prevent regressions. Knip does
the same for dependencies, exports and files that are obsolete.
- Keeping dead code around has a negative value on readability, as it can be
misleading and distracting. Even if it serves no purpose it will need to be
maintained (source:Safe dead code removal → YAGNI).
- Also seeWhy are unused dependencies a problem?andWhy are unused
exports a problem?.
## Automation
Code and dependency management is usually not the most exciting task for most of
us. Knip’s mission is to automate finding clutter. This is such a tedious job if
you were to do it manually, and where would you even start? Knip applies many
techniques and heuristics to report what you need and save a lot of time.
Knip not only finds clutter, it can alsoremove clutter!
Use Knip next to a linter like ESLint or Biome: after removing unused variables
inside files, Knip might find even more unused code. Rinse and repeat!
## Comprehensive
You can use alternative tools that do the same. However, the advantage of a
strategy that addresses all of dependencies, exports and files is in their
synergy:
- Utilizing plugins to find their dependencies includes the capacity to find
additional entry and configuration files. This results in more resolved and
used files. Better coverage gives better insights into unused files and
exports.
- Analyzing more files reveals more unused exports and dependency usage,
refining the list of both unused and unlisted dependencies.
- This approach is amplified in a monorepo setting. In fact, files and internal
dependencies can recursively reference each other (across workspaces).
## Greenfield or Legacy
Installing Knip in greenfield projects ensures the project stays neat and tidy
from the start. Add it to your CI workflow and prevent any regressions from
entering the codebase.
Use Knip in a CI environment to prevent future regressions.
In large and/or legacy projects, Knip may report false positives and require
some configuration. It aims to be a great assistant when cleaning up parts of
the project or doing large refactors. Even a list of results with a few false
positives is many times better and faster than if you were to do it manually.
## Unobtrusive
Knip does not introduce new syntax for you to learn. This may sound obvious, but
consider comments like the following:
```typescript
// eslint-disable-next-line// prettier-ignore// @ts-expect-error
```
Maybe you wonder why Knip does not have similar comments like// knip-ignoreso you can get rid of false positives? A variety of reasons:
- A false positive may be a bug in Knip, and should be reported, not dismissed.
- Instead of proprietary comments, usestandardized annotationsthat also
serve as documentation.
- In the event you want to remove Knip, just uninstallknipwithout having to
remove useless comments scattered throughout the codebase.
Tip: use@lintignorein JSDoc comments, so other linters can use the same.
ISC License© 2024Lars Kappert
---
# Auto-fix
Source: https://knip.dev/features/auto-fix
Run Knip as you normally would, and if the report looks good then run it again
with the--fixflag to let Knip automatically apply fixes. It fixes the
followingissue types:
- Removeexportkeyword for unused exports and exported types
- Removeexport defaultkeywords for unused default exports
- Remove exports, re-exports and exported types
- Remove unused enum members
- Remove unused class members (disabled by default)
- Remove unuseddependenciesanddevDependenciesfrompackage.json
- Remove unused files
Use a VCS (version control system) like Git to review and undo changes as
necessary.
## Flags
### Fix
Add the--fixflag to remove unused exports and dependencies:
```typescript
knip--fix
```
Add--allow-remove-filesto allow Knip to remove unused files:
```typescript
knip--fix--allow-remove-files
```
Use--fix-typeto fix only specific issue types:
- files
- exports
- types
- dependencies
- catalog
```typescript
knip--fix-typeexports,typesknip--fix-typeexports--fix-typetypes# same as above
```
### Format
Add--formatto format the modified files using the formatter and
configuration in your project. Supports Biome, deno fmt, dprint and Prettier
(usingFormatly):
```typescript
knip--fix--format
```
## Demo
## Post-fix
After Knip has fixed issues, there are four things to consider:
### 1. Use a formatter
Use a tool like Prettier or Biome if the code needs formatting. Knip removes the
minimum amount of code while leaving it in a working state.
Add the--formatflag to format the modified files using the formatter and
configuration in your project.
### 2. Unused variables
Use a tool like ESLint or Biome to find and remove unused variables inside
files. Even better, tryremove-unused-varsto remove unused variables
within files.
This may result in more deleted code, and Knip may then find more unused code.
Rinse and repeat!
### 3. Unused dependencies
Verify changes inpackage.jsonand update dependencies using your package
manager.
- npm
- pnpm
- bun
- yarn
```typescript
npminstall
```
```typescript
pnpminstall
```
```typescript
buninstall
```
```typescript
yarn
```
### 4. Install unlisted dependencies
If Knip reports unlisted dependencies or binaries, they should be installed
using the package manager in the project, for example:
- npm
- pnpm
- bun
- yarn
```typescript
npminstallunlisted-package
```
```typescript
pnpmaddunlisted-package
```
```typescript
bunaddunlisted-package
```
```typescript
yarnaddunlisted-package
```
## Example results
### Exports
Theexportkeyword for unused exports is removed:
```typescript
export const unused = 1;export default class MyClass {}const unused = 1;class MyClass {}
```
Thedefaultkeyword was also removed here.
Knip removes the whole or part of export declarations:
```typescript
type Snake = 'python' | 'anaconda';const Owl = 'Hedwig';const Hawk = 'Tony';export type { Snake };export { Owl, Hawk };;;
```
### Re-exports
Knip removes the whole or part of re-exports:
```typescript
export { Cat, Dog } from './pets';export { Lion, Elephant } from './jungle';export { Elephant } from './jungle'
```
Also across any chain of re-exports:
- module.ts
- barrel.ts
- index.ts
```typescript
export const Hawk = 'Tony';export const Owl = 'Hedwig';const Owl = 'Hedwig';
```
```typescript
export * from './module.js';
```
```typescript
export { Hawk, Owl } from './barrel.js';export { Hawk } from './barrel.js'
```
### Export assignments
Knip removes individual exported items in “export assignments”, but does not
remove the entire export declaration if it’s empty:
```typescript
export const { a, b } = fn();export const { } = fn();export const [c, d] = [c, d];export const [, ] = [c, d];
```
Reason: the right-hand side of the assignment might have side-effects. It’s not
safe to always remove the whole declaration. This could be improved in the
future (feel free to open an issue/RFC).
### Enum members
Unused members of enums are removed:
```typescript
export enum Directions {North = 1,East = 2,South = 3,West = 4,}
```
### CommonJS
Knip supports CommonJS and removes unused exports:
```typescript
module.exports = { identifier, unused };module.exports = { identifier, };module.exports.UNUSED = 1;module.exports['ACCESS'] = 1;
```
Warning: the right-hand side of such an assignment might have side-effects. Knip
currently removes the whole declaration (feel free to open an issue/RFC).
### Dependencies
Unused dependencies are removed frompackage.json:
```typescript
{"name": "my-package","dependencies": {"rimraf": "*","unused-dependency": "*""rimraf": "*"},"devDependencies": {"unreferenced-package": "5.3.3"}"devDependencies": {}}
```
### Class membersexperimental
Unused members of classes can be removed:
```typescript
export class Rectangle {constructor(public width: number, public height: number) {}static Key = 1;area() {return this.width * this.height;}public get unusedGetter(): string {return 'unusedGetter';}}
```
Currently Knip might be too eager removing class members when they’re not
referenced internally but meant to be called by an external library. For
instance, Knip might thinkcomponentDidMountandrenderin React class
component are unused and will remove those.
Note thatclassMembersaren’t included by default.
## What’s not included
Operations that auto-fix does not (yet) perform and why:
- Add unlisted (dev) dependencies topackage.json(should it go intodependenciesordevDependencies? For monorepos in current workspace or
root?)
- Add unlisted binaries (which package and package version contains the used
binary?)
- Fix duplicate exports (which one should be removed?)
ISC License© 2024Lars Kappert
---
# Compilers
Source: https://knip.dev/features/compilers
Projects may have source files that are not JavaScript or TypeScript, and thus
require compilation (or transpilation, or pre-processing, you name it). Files
like.mdx,.astro,.vueand.sveltemay also import other source files
and external dependencies. So ideally, these files are included when linting the
project. That’s why Knip supports compilers.
## Built-in compilers
Knip has built-in “compilers” for the following file extensions:
- .astro
- .css(only enabled bytailwindcss)
- .mdx
- .prisma
- .sass+.scss
- .svelte
- .vue
Knip does not include real compilers for those files, but regular expressions to
collectimportstatements. This is fast, requires no dependencies, and enough
for Knip to build the module graph.
On the other hand, real compilers may expose their own challenges in the context
of Knip. For instance, the Svelte compiler keepsexportsintact, while they
might represent component properties. This results in those exports being
reported as unused by Knip.
The built-in functions seem to do a decent job, but override them however you
like.
Compilers are enabled only if certain dependencies are found. If that’s not
working for your project, settrueand enable any compiler manually:
```typescript
exportdefault{compilers:{mdx:true,},};
```
## Custom compilers
Built-in compilers can be overridden, and additional compilers can be added.
Since compilers are functions, the Knip configuration file must be a dynamic.jsor.tsfile.
### Interface
The compiler function interface is straightforward. Text in, text out:
```typescript
(source:string,filename:string)=>string;
```
This may also be anasyncfunction.
Compilers will automatically have their extension added as a default extension
to Knip. This means you don’t need to add something like**/*.{ts,vue}to theentryorprojectfile patterns manually.
### Examples
- CSS
- MDX
- Svelte
- Vue
#### CSS
Here’s an example, minimal compiler for CSS files:
```typescript
exportdefault{compilers:{css:(text:string)=>[...text.matchAll(/(?<=@)import[^;]+/g)].join('\n'),},};
```
You may wonder why the CSS compiler is not included by default. It’s currently
not clear if it should be included. And if so, what would be the best way to
determine it should be enabled, and what syntax(es) it should support. Note that
Tailwind CSS and SASS/SCSS compilers are included.
#### MDX
Another example, in case the built-in MDX compiler is not enough:
```typescript
import{ compile }from'@mdx-js/mdx';exportdefault{compilers:{mdx:asynctext=>(awaitcompile(text)).toString(),},};
```
#### Svelte
In a Svelte project, the compiler is automatically enabled. Override and use
Svelte’s compiler for better results if the built-in “compiler” is not enough:
```typescript
importtype{ KnipConfig }from'knip';import{ compile }from'svelte/compiler';exportdefault{compilers:{svelte:(source:string)=>compile(source,{}).js.code,},}satisfiesKnipConfig;
```
#### Vue
In a Vue project, the compiler is automatically enabled. Override and use Vue’s
parser for better results if the built-in “compiler” is not enough:
```typescript
importtype{ KnipConfig }from'knip';import{parse,typeSFCScriptBlock,typeSFCStyleBlock,}from'vue/compiler-sfc';functiongetScriptBlockContent(block:SFCScriptBlock|null):string[] {if(!block)return[];if(block.src)return[`import '${block.src}'`];return[block.content];}functiongetStyleBlockContent(block:SFCStyleBlock|null):string[] {if(!block)return[];if(block.src)return[`@import '${block.src}';`];return[block.content];}functiongetStyleImports(content:string):string{return[...content.matchAll(/(?<=@)import[^;]+/g)].join('\n');}constconfig={compilers:{vue:(text:string,filename:string)=>{const{descriptor}=parse(text,{ filename,sourceMap:false});return[...getScriptBlockContent(descriptor.script),...getScriptBlockContent(descriptor.scriptSetup),...descriptor.styles.flatMap(getStyleBlockContent).map(getStyleImports),].join('\n');},},}satisfiesKnipConfig;exportdefaultconfig;
```
ISC License© 2024Lars Kappert
---
# Integrated Monorepos
Source: https://knip.dev/features/integrated-monorepos
Some repositories have a singlepackage.json, but consist of multiple projects
with configuration files across the repository. A good example is theNx
integrated monorepo style.
An integrated monorepo is a single workspace.
## Entry Files
The default entrypoints files might not be enough. Here’s an idea that might fit
this type of monorepo:
```typescript
{"entry":["{apps,libs}/**/src/index.{ts,tsx}"],"project":["{apps,libs}/**/src/**/*.{ts,tsx}"]}
```
## Plugins
Let’s assume some of these projects are applications (“apps”) which have their
own ESLint configuration files and Cypress configuration and test files. This
may result in those files getting reported as unused, and consequently also the
dependencies they import and refer to.
In that case, we could configure the ESLint and Cypress plugins like this:
```typescript
{"eslint":{"config":["{apps,libs}/**/.eslintrc.json"]},"cypress":{"entry":["apps/**/cypress.config.ts","apps/**/cypress/e2e/*.spec.ts"]}}
```
Adapt the file patterns to your project, and the relevantconfigandentryfiles and dependencies should no longer be reported as unused.
## Internal Workspace Dependencies
A note about repositories with multiplepackage.jsonfiles andinternalworkspace packages: it is recommended to list all dependencies in each consumingpackage.json, allowing Knip to do fine-grained reporting of both unused and
unlisted dependencies.
An alternative is toignoreDependencies: ["@internal/*"].
ISC License© 2024Lars Kappert
---
# Monorepos & Workspaces
Source: https://knip.dev/features/monorepos-and-workspaces
Workspaces are handled out-of-the-box by Knip.
Workspaces are sometimes also referred to as package-based monorepos, or as
packages in a monorepo. Knip uses the term workspace exclusively to indicate a
directory that has apackage.json.
## Configuration
Here’s example configuration with customentryandprojectpatterns:
```typescript
{"workspaces":{".":{"entry":"scripts/*.js","project":"scripts/**/*.js"},"packages/*":{"entry":"{index,cli}.ts","project":"**/*.ts"},"packages/cli":{"entry":"bin/cli.js"}}}
```
Run Knip without any configuration to see if and where customentryand/orprojectfiles are necessary per workspace.
Each workspace has the samedefault configuration.
The root workspace is named"."underworkspaces(like in the example
above).
In a project with workspaces, theentryandprojectoptions at the root
level are ignored. Use the workspace named"."for those (like in the example
above).
## Workspaces
Knip reads workspaces from four possible locations:
- Theworkspacesarray inpackage.json(npm, Bun, Yarn, Lerna)
- Thepackagesarray inpnpm-workspace.yaml(pnpm)
- Theworkspaces.packagesarray inpackage.json(legacy)
- Theworkspacesobject in Knip configuration
Theworkspacesin Knip configuration (4) not already defined in the rootpackage.jsonorpnpm-workspace.yaml(1, 2, 3) are added to the analysis.
A workspace must have apackage.jsonfile.
For projects with only a rootpackage.json, please seeintegrated
monorepos.
## Additional workspaces
If a workspaces is not configured as such inpackage.json#workspaces(orpnpm-workspace.yaml) it can be added to the Knip configuration manually. Add
their path to theworkspacesconfiguration object the same way as"packages/cli": {}in the example above.
## Source mapping
SeeSource Mapping.
## Additional options
The following options are available inside workspace configurations:
- ignore
- ignoreBinaries
- ignoreDependencies
- ignoreMembers
- ignoreUnresolved
- includeEntryExports
Pluginscan be configured separately per workspace.
Use--debugfor verbose output and see the workspaces Knip includes, their
configurations, enabled plugins, glob options and resolved files.
## Lint a single workspace
Use the--workspace(or-W) argument to focus on a single workspace (and let
Knip run faster). Example:
```typescript
knip--workspacepackages/my-lib
```
This will include the target workspace, but also ancestor and dependent
workspaces. For two reasons:
- Ancestor workspaces may list dependencies inpackage.jsonthe linted
workspace uses.
- Dependent workspaces may reference exports from the linted workspace.
To lint the workspace in isolation, there are two options:
- Combine theworkspaceargument withstrict production mode.
- Run Knip from inside the workspace directory.
ISC License© 2024Lars Kappert
---
# Production Mode
Source: https://knip.dev/features/production-mode
The default mode for Knip is comprehensive and targets all project code,
including configuration files, test files, Storybook stories, and so on. Test
files usually import production files. This prevents production files or their
exports from being reported as unused, while sometimes both of them can be
deleted. Knip features a “production mode” to focus only on the code that you
ship.
## Configuration
To tell Knip what is production code, add an exclamation mark behind eachpattern!that represents production code:
```typescript
{"entry":["src/index.ts!","build/script.js"],"project":["src/**/*.ts!","build/*.js"]}
```
Depending on file structure and enabled plugins, you might not need to modify
your configuration at all.
Run Knip with the--productionflag:
```typescript
knip--production
```
Here’s what’s included in production mode:
- Onlyentryandprojectpatterns suffixed with!
- Only productionentryfile patterns exported by plugins (such as Next.js and
Remix)
- Only thestartandpostinstallscripts
- Ignore exports with the@internaltag
The production run does not replace the default run. Depending on your needs you
can run either of them or both separately. Usually both modes can share the same
configuration.
To see the difference between default and production mode in great detail, use
the--debugflag and inspect what entry and project files are used, and the
plugins that are enabled. For instance, in production mode this shows that files
such as tests and Storybook files (stories) are excluded from the analysis.
In case files like mocks and test helpers are reported as unused files, use
negated patterns to exclude those files in production mode:
```typescript
{"entry":["src/index.ts!"],"project":["src/**/*.ts!","!src/test-helpers/**!"]}
```
Also seeconfiguring project filesto alignentryandprojectwith
production mode.
## Strict Mode
In production mode, onlydependencies(notdevDependencies) are considered
when finding unused or unlisted dependencies.
Additionally, the--strictflag can be added to:
- Verify isolation: workspaces should use strictly their owndependencies
- IncludepeerDependencieswhen finding unused or unlisted dependencies
- Report type-only imports listed independencies
```typescript
knip--production--strict
```
Using--strictimplies--production, so the latter can be omitted.
## Types
Add--exclude typesif you don’t want to include types in the report:
```typescript
knip--production--excludetypes
```
ISC License© 2024Lars Kappert
---
# Reporters & Preprocessors
Source: https://knip.dev/features/reporters
## Built-in Reporters
Knip provides the following built-in reporters:
- codeowners
- compact
- disclosure
- github-actions
- json
- markdown
- codeclimate
- symbols(default)
Example usage:
```typescript
knip--reportercompact
```
### JSON
The built-injsonreporter output is meant to be consumed by other tools. It
reports in JSON format with unusedfilesandissuesas an array with one
object per file structured like this:
```typescript
{"files":["src/unused.ts"],"issues":[{"file":"package.json","owners":["@org/admin"],"dependencies":[{"name":"jquery","line":5,"col":6,"pos":71}],"devDependencies":[{"name":"lodash","line":9,"col":6,"pos":99}],"unlisted":[{"name":"react"},{"name":"@org/unresolved"}],"exports":[],"types":[],"duplicates":[]},{"file":"src/Registration.tsx","owners":["@org/owner"],"dependencies":[],"devDependencies":[],"binaries":[],"unresolved":[{"name":"./unresolved","line":8,"col":23,"pos":407}],"exports":[{"name":"unusedExport","line":1,"col":14,"pos":13}],"types":[{"name":"unusedEnum","line":3,"col":13,"pos":71},{"name":"unusedType","line":8,"col":14,"pos":145}],"enumMembers":{"MyEnum":[{"name":"unusedMember","line":13,"col":3,"pos":167},{"name":"unusedKey","line":15,"col":3,"pos":205}]},"classMembers":{"MyClass":[{"name":"unusedMember","line":40,"col":3,"pos":687},{"name":"unusedSetter","line":61,"col":14,"pos":1071}]},"duplicates":["Registration","default"]}]}
```
The keys match thereported issue types. Example usage:
```typescript
knip--reporterjson
```
### Github Actions
Example usage:
```typescript
knip--reportergithub-actions
```
### Markdown
The built-inmarkdownreporter output is meant to be saved to a Markdown file.
This allows following the changes in issues over time. It reports issues in
Markdown tables separated by issue types as headings, for example:
```typescript
# Knip report## Unused files (1)- src/unused.ts## Unlisted dependencies (2)| Name | Location | Severity ||:--------------|:----------------|:-------|| unresolved | src/index.ts:8:23 | error || @org/unresolved | src/index.ts:9:23 | error |## Unresolved imports (1)| Name | Location | Severity ||:-----------|:-----------------|:-------|| ./unresolved | src/index.ts:10:12 | error |
```
### Disclosure
This reporter is useful for sharing large reports. Groups of issues are rendered
in a closed state initially. The reporter renders this:
```typescript
$ knip --reporter disclosureUnused files (2)
```unused.tsdangling.js```Unused dependencies (2)
```unused-dep package.jsonmy-package package.json```
```
The above can be copy-pasted where HTML and Markdown is supported, such as a
GitHub issue or pull request, and renders like so:
```typescript
unused.tsdangling.js
```
```typescript
unused-dep package.jsonmy-package package.json
```
### CodeClimate
The built-incodeclimatereporter generates output in the Code Climate Report
JSON format. Example usage:
```typescript
$ knip --reporter codeclimate[{"type": "issue","check_name": "Unused exports","description": "isUnused","categories": ["Bug Risk"],"location": {"path": "path/to/file.ts","positions": {"begin": {"line": 6,"column": 1}}}"severity": "major","fingerprint": "e9789995c1fe9f7d75eed6a0c0f89e84",}]
```
## Custom Reporters
When the provided built-in reporters are not sufficient, a custom local reporter
can be implemented or an external reporter can be used. Multiple reporters can
be used at once by repeating the--reporterargument.
The results are passed to the function from its default export and can be used
to write issues tostdout, a JSON or CSV file, or sent to a service. It
supports a local JavaScript or TypeScript file or an external dependency.
### Local
The default export of the reporter should be a function with this interface:
```typescript
typeReporter=async(options:ReporterOptions):void;typeReporterOptions={report:Report;issues:Issues;counters:Counters;configurationHints:ConfigurationHints;isDisableConfigHints:boolean;isTreatConfigHintsAsErrors:boolean;cwd:string;isProduction:boolean;isShowProgress:boolean;options:string;};
```
The data can then be used to write issues tostdout, a JSON or CSV file, or
sent to a service.
Here’s a most minimal reporter example:
```typescript
importtype{ Reporter }from'knip';constreporter:Reporter=function(options) {console.log(options.issues);console.log(options.counters);};exportdefaultreporter;
```
Example usage:
```typescript
knip--reporter./my-reporter.ts
```
### External
Pass--reporter [pkg-name]to use an external reporter. The default exported
function of themainscript (default:index.js) will be invoked with theReporterOptions, just like a local reporter.
## Preprocessors
A preprocessor is a function that runs after the analysis is finished. It
receives the results from the analysis and should return data in the same
shape/structure (unless you pass it to only your own reporter).
The data goes through the preprocessors before the final data is passed to the
reporters. There are no built-in preprocessors. Just like reporters, use e.g.--preprocessor ./my-preprocessorfrom the command line (can be repeated).
The default export of the preprocessor should be a function with this interface:
```typescript
typePreprocessor=async(options:ReporterOptions)=>ReporterOptions;
```
Like reporters, you can use local JavaScript or TypeScript files and external
npm packages as preprocessors.
Example preprocessor:
```typescript
importtype{ Preprocessor }from'knip';constpreprocess:Preprocessor=function(options) {// modify options.issues and options.countersreturnoptions;};exportdefaultpreprocess;
```
Example usage:
```typescript
knip--preprocessor./preprocess.ts
```
ISC License© 2024Lars Kappert
---
# Rules & Filters
Source: https://knip.dev/features/rules-and-filters
Use rules or filters to customize Knip’s output. This has various use cases, a
few examples:
- Temporarily focus on a specific issue type.
- You don’t want to see unusedtype,interfaceandenumexports reported.
- Specific issue types should be printed, but not counted against the total
error count.
If you’re looking to handle one-off exceptions, also seeJSDoc tags.
## Filters
You can--includeor--excludeany of the reported issue types to slice &
dice the report to your needs. Alternatively, they can be added to the
configuration (e.g."exclude": ["dependencies"]).
Use--includeto report only specific issue types. The following example
commands do the same:
```typescript
knip--includefiles--includedependenciesknip--includefiles,dependencies
```
Or the other way around, use--excludeto ignore the types you’re not
interested in:
```typescript
knip--includefiles--excludeenumMembers,duplicates
```
Also see thelist of issue types.
### Shorthands
Knip has shortcuts to include only specific issue types.
- The--dependenciesflag includes:dependencies(anddevDependencies+optionalPeerDependencies)unlistedbinariesunresolvedcatalog
- The--exportsflag includes:exportstypesenumMembersduplicates
- The--filesflag is a shortcut for--include files
The--dependenciesflag includes:
- dependencies(anddevDependencies+optionalPeerDependencies)
- unlisted
- binaries
- unresolved
- catalog
The--exportsflag includes:
- exports
- types
- enumMembers
- duplicates
The--filesflag is a shortcut for--include files
## Rules
Userulesin the configuration to customize the issue types that count towards
the total error count, or to exclude them altogether.
```typescript
{"rules":{"files":"warn","classMembers":"off","duplicates":"off"}}
```
Also see theissue types overview.
NOTE: If thedependenciesissue type is included, thedevDependenciesandoptionalPeerDependenciestypes can still be set to"warn"separately.
The rules are modeled after the ESLintrulesconfiguration, and could be
extended in the future.
## Rules or filters?
Filters are meant to be used as command-line flags, rules allow for more
fine-grained configuration.
- Rules are more fine-grained since they also have “warn”.
- Rules could be extended in the future.
- Filters can be set in configuration and from CLI (rules only in
configuration).
- Filters have shorthands (rules don’t have this).
ISC License© 2024Lars Kappert
---
# Script Parser
Source: https://knip.dev/features/script-parser
Knip parses shell commands and scripts to find additional dependencies, entry
files and configuration files in various places:
- Inpackage.json
- InCLI arguments
- Inscripts
- Insource code
Shell scripts can be read and statically analyzed, but they’re not executed.
## package.json
Themain,bin,exportsandscriptsfields may contain entry files. Let’s
take a look at this example:
```typescript
{"name":"my-package","main":"index.js","exports":{"./lib":{"import":"./dist/index.mjs","require":"./dist/index.cjs"}},"bin":{"program":"bin/cli.js"},"scripts":{"build":"rollup src/entry.ts","start":"node --loader tsx server.ts"}}
```
From this example, Knip automatically adds the following files as entry files:
- index.js
- ./dist/index.mjs
- ./dist/index.cjs
- bin/cli.js
- src/entry.ts
- server.ts
### Excluded files
Knip would not add theexportsif thedistfolder is matching a pattern in a
relevant.gitignorefile orignoreoption.
Knip does not add scripts without a standard extension. For instance, thebin/toolfile might be a valid executable for Node.js, but wouldn’t be added
or parsed by Knip.
### CLI Arguments
When parsing thescriptsofpackage.jsonand other files, Knip detects
various types of inputs. Some examples:
- The first positional argument is usually an entry file
- Configuration files are often in the-cor--configargument
- The--require,--loaderor--importarguments are often dependencies
```typescript
{"name":"my-lib","scripts":{"start":"node --import tsx/esm run.ts","bundle":"tsup -c tsup.lib.config.ts","type-check":"tsc -p tsconfig.app.json"}}
```
The"start"script will havetsxmarked as a referenced dependency, and addsrun.tsas an entry file.
Additionally, the following files are detected as configuration files:
- tsup.lib.config.ts- to be handled by the tsup plugin
- tsconfig.app.json- to be handled by the TypeScript plugin
Such executables and their arguments are all defined in plugins separately for
fine-grained results.
## Scripts
Plugins may also use the script parser to extract entry files and dependencies
from commands. A few examples:
- GitHub Actions: workflow files may containruncommands (e.g..github/workflows/ci.yml)
- Husky & Lefthook: Git hooks such as.git/hooks/pre-pushcontain scripts;
alsolefthook.ymlhasruncommands
- Lint Staged: configuration values are all commands
- Nx: task executors andnx:run-commandsexecutors inproject.jsoncontains
scripts
- Release It:hookscontain commands
Plugins can also return configuration files. Some examples:
- The Angular plugin detectsoptions.tsConfigas a TypeScript config file
- The GitHub Actions plugin parsesruncommands which may contain
configuration file paths
## Source Code
When Knip is walking the abstract syntax trees (ASTs) of JavaScript and
TypeScript source code files, it looks for imports and exports. But there’s a
few more (rather obscure) things that Knip detects in the process. Below are
examples of additional scripts Knip parses to find entry files and dependencies.
### bun
If thebundependency is imported in source code, Knip considers the contents
of$template tags to be scripts:
```typescript
import{ $ }from'bun';await$`bun boxen I ❤ unicorns`;await$`boxen I ❤ unicorns`;
```
Parsing the script results in theboxenbinary (theboxen-clidependency) as
referenced (twice).
### execa
If theexecadependency is imported in source code, Knip considers the
contents of$template tags to be scripts:
```typescript
await$({ stdio:'inherit'})`c8 node hydrate.js`;
```
Parsing the script results inhydrate.jsadded as an entry file and thec8binary/dependency as referenced.
### zx
If thezxdependency is imported in source code, Knip considers the contents
of$template tags to be scripts:
```typescript
await$`node scripts/parse.js`;
```
This will addscripts/parse.jsas an entry file.
ISC License© 2024Lars Kappert
---
# Source Mapping
Source: https://knip.dev/features/source-mapping
Knip is mostly interested in source code. Analyzing build artifacts hurts
performance and often leads to false positives, as they potentially contain
bundled code and unresolvable imports.
That’s why Knip tries to map such build artifacts back to their original source
files and analyze those instead. This is done based ontsconfig.jsonsettings.
## Example 1: package.json
Let’s look at an example case withpackage.jsonandtsconfig.jsonfiles, and
see how “dist” files are mapped to “src” files.
```typescript
{"name":"my-workspace","main":"index.js","exports":{".":"./src/entry.js","./feat":"./lib/feat.js","./public":"./dist/app.js","./public/*":"./dist/*.js","./public/*.js":"./dist/*.js","./dist/internal/*":null,},}
```
With this TypeScript configuration:
```typescript
{"compilerOptions":{"baseUrl":"src","outDir":"dist"}}
```
- ./src/entry.jsis not in anoutDirfolder, so it’s added as an entry file
- ./lib/feat.jsis not in anoutDirfolder, so it’s added as an entry file
- ./dist/app.jsis in adistfolder and mapped to./src/app.{js,ts}(¹)
- ./dist/*.jsis in adistfolder and mapped to./src/**/*.{js,ts}(¹)
- ./dist/internal/*is translated to./dist/internal/**and files in this
directory and deeper are ignored when globbing entry files
(¹) full extensions list is actually:js,mjs,cjs,jsx,ts,tsx,mts,cts
In--debugmode, look for “Source mapping” to see this in action.
Using./dist/*.jsmeans that all files matching./src/**/*.{js,ts}are added
as entry files. By default, unused exports of entry files are not reported. UseincludeEntryExportsto include them.
## Example 2: monorepo
Let’s say we have this module in a monorepo that importshelperfrom another
workspace in the same monorepo:
```typescript
import{ helper }from'@org/shared';
```
The target workspace@org/sharedhas thispackage.json:
```typescript
{"name":"@org/shared","main":"dist/index.js"}
```
The module resolver will resolve@org/sharedtodist/index.js. That file is
usually compiled and git-ignored, while Knip wants the source file instead.
You may need to compile build artifacts tooutDirfirst before Knip can
successfully apply source mapping for internal references in a monorepo.
If the target workspace has atsconfig.jsonfile with anoutDiroption, Knip
will try to map the “dist” file to the “src” file. Then ifsrc/index.tsexists, Knip will use that file instead ofdist/index.js.
Currently this only works based ontsconfig.json, in the future more source
mappings may be added.
ISC License© 2024Lars Kappert
---
# Configuring Project Files
Source: https://knip.dev/guides/configuring-project-files
Theentryandprojectfile patterns are the first and most important
options. Getting those right is essential to help you delete more code and make
Knip faster:
- Start with defaults. Only add targetedentryoverrides when needed.
- Useprojectpatterns (with negations) to define the scope for Knip.
- Use production mode to exclude tests and other non-production files.
- Useignoreonly to suppress issues in specific files; it does not exclude
files from analysis.
Let’s dive in and expand on all of these.
## Entry files
Avoid adding too many files asentryfiles:
- Knip does not reportunused exportsin entry files by default.
- Properentryandprojectpatterns allow Knip to find unused files and
exports.
## Unused files
Files are reported as unused if they are in the set ofprojectfiles, but are
not resolved from theentryfiles:
```typescript
unused files = project files - (entry files + resolved files)
```
Seeentry filesto see where Knip looks for entry files. Fine-tuneentryand adjustprojectto fit your codebase.
Use negatedprojectpatterns to precisely include/exclude files for unused
files detection.
Useignore*to suppress specific issues in matching files; it does not exclude
files from analysis.
## Negated patterns
When there are too many files in the analysis, start here.
For instance, routes are entry files except those prefixed with an underscore:
```typescript
{"entry":["src/routes/*.ts","!src/routes/_*.ts"]}
```
Some files are not part of your source and are reported as unused (false
positives)? Use negatedprojectpatterns:
```typescript
{"entry":["src/index.ts"],"project":["src/**/*.ts","!src/exclude/**"]}
```
❌ Don’t useignorefor generated artifacts:
```typescript
{"entry":["src/index.ts","scripts/*.ts"],"ignore":["build/**","dist/**","src/generated.ts"]}
```
✅ Do define your project boundaries:
```typescript
{"entry":["src/index.ts","scripts/*.ts"],"project":["src/**","scripts/**"],"ignore":["src/generated.ts"]}
```
Why this is better:
- projectdefines what belongs to the codebase, so build outputs are excluded
from analysis and unused file detection
- ignoreis for the few files that should be analyzed but contain exceptions
- Improves performance by analyzing fewer files
## Ignore issues in specific files
Useignorewhen a specific analyzed file is not handled properly by Knip or
intentionally contains unused exports (e.g. generated files exporting
“everything”):
```typescript
{"entry":["src/index.ts"],"project":["src/**/*.ts"],"ignore":["src/generated.ts"]}
```
Also seeignoreExportsUsedInFilefor a more targeted approach.
## Production Mode
Default mode includes tests and other non-production files in the analysis. To
focus on production code, useproduction mode.
Don’t try to exclude tests viaignoreor negatedprojectpatterns. That’s
inefficient and ineffective due to entries added by plugins. Use production mode
instead.
❌ Don’t do this:
```typescript
{"ignore":["**/*.test.js"]}
```
Why not:ignorehides issues from the report; it does not exclude files from
analysis.
❌ Also don’t do this:
```typescript
{"entry":["index.ts","!**/*.test.js"]}
```
Why not: plugins add test files asentryfiles; you can’t and shouldn’t
override that globally.
❌ Or this:
```typescript
{"project":["**/*.ts","!**/*.spec.ts"]}
```
Why not:projectis for unused file detection; negating test files is
ineffective because they areentryfiles.
✅ Do this instead:
```typescript
knip--production
```
To fine-tune the resulting production file set, for instance to exclude test
helper files that still show as unused, use the exclamation mark suffix on
production patterns:
```typescript
{"entry":["src/index.ts!"],"project":["src/**/*.ts!","!src/test-helpers/**!"]}
```
Remember to keep adding the exclamation marksuffix!for production file
patterns.
Use the exclamation mark (!) on both ends (!) to exclude files in production
mode.
## Defaults & Plugins
To reiterate, the defaultentryandprojectfiles for each workspace:
```typescript
{"entry":["{index,cli,main}.{js,cjs,mjs,jsx,ts,cts,mts,tsx}","src/{index,cli,main}.{js,cjs,mjs,jsx,ts,cts,mts,tsx}"],"project":["**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}!"]}
```
Next to this, there are other places whereKnip looks for entry files.
Additionally,plugins have plenty of entry files configuredthat are
automatically added as well.
ISC License© 2024Lars Kappert
---
# Contributing to Knip
Source: https://knip.dev/guides/contributing
Here are some ways to contribute to Knip:
- Spread the word!
- Star the project
- File an issue with a reproduction
- Pull requests are welcome
Writing a pluginis a great and fun way to get started.
TheCONTRIBUTING.mdandDEVELOPMENT.mdguides should get you up and
running quickly.
The main goal of Knip is to keep projects clean & tidy. Everything that
contributes to that goal is welcome!
ISC License© 2024Lars Kappert
---
# Handling Issues
Source: https://knip.dev/guides/handling-issues
Issues reported by Knip may contain false positives, but also tons of useful
information. Getting the most out of Knip may require some configuration.
Go over the issue types one by one. For instance, reducing the number of unused
files will also reduce the number of unused dependencies.
- Unused files
- Unused dependencies
- Unresolved imports
- Unused exports
## Unused files
Getting the list of unused files right trickles down into the other issue types
as well, so we start here. Files are reported as unused if they are in the set
ofprojectfiles, but not in the set of files resolved from theentryfiles:
```typescript
unused files = project files - (entry files + resolved files)
```
Let’s go over common causes for unused files:
- Missing generated files
- Dynamic import specifiers
- Unsupported arguments in scripts
- Unsupported file formats
- Missing plugin
- Incomplete plugin
- TypeScript path aliases in monorepos
- Relative paths across workspaces
- Integrated monorepos
- Auto-mocking or auto-imports
In most cases you can addentrypatterns manually.
Use--filestofilter the reportand focus only on unused files:
```typescript
knip--files
```
This works with other issue types as well. For instance, use--dependenciesto
focus only on dependencies and exclude issues related to unused files and
exports.
Don’t add unused files to theignoreoption before readingconfiguring
project files. Learn why and when to useentry,project, production
mode andignorepatterns for better results and performance.
### Missing generated files
For certain features, Knip needs to run after relevant files are generated. For
instance,source mappingin a monorepo may require files to be built intodistfolders first. And generated files in thesrcdirectory may import
other files. For instance, thesrc/routeTree.gen.tsfile generated by@tanstack/routermust exist so Knip can find the imported route files.
Solution: compile and/or generate the relevant files first so Knip can
resolve and find the source files.
If Knip still reports false positives, you may need to strategically add anentryfile manually.
### Dynamic import specifiers
Dynamic import specifiers aren’t resolved, such as:
```typescript
constentry=awaitimport(path.join(baseDir,'entry.ts'));
```
Solution: addentry.tstoentrypatterns.
### Unsupported arguments in scripts
Some tooling command arguments aren’t recognized:
```typescript
{"name":"my-lib","version":"1.0.0","scripts":{"build":"unknown-build-cli --entry production.ts"}}
```
Solution: addproduction.tstoentrypatterns.
This works the same for any script, also those in GitHub Actions workflows or
Git hooks. Seescript parserfor more details about Knip’s script parser.
### Unsupported file formats
Entry files referenced in HTML files (e.g.