# 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 disclosure
Unused 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. ``` Solution: addproduction.jstoentrypatterns. Or add an.htmlcompiler to extract and resolve the value of