Knip — Dead Code & Dependency Cleanup
Knip finds unused files, dependencies, exports, types, and duplicate packages in JavaScript/TypeScript projects. Use this skill to analyze, report, and safely clean up projects.
What Knip Detects
| Category | Description | Risk Level |
|---|---|---|
| Unused files | Source files not imported anywhere | Medium |
| Unused dependencies | Packages in dependencies/devDependencies not imported |
High — safe to remove |
| Unlisted dependencies | Packages imported but not in package.json |
Critical — must add |
| Unused exports | Named exports not consumed by other modules | Low — may be public API |
| Unused types | TypeScript types/interfaces not referenced | Low |
| Duplicate packages | Same package at multiple versions in lockfile | Medium |
| Unused binaries | Binaries declared but not used in scripts | Low |
| Unresolved imports | Imports that point to missing modules | Critical |
Installation
# Install as dev dependency (recommended)
pnpm add -D knip
# Or run without installing
pnpm dlx knip
Configuration
Knip works zero-config for many projects but supports knip.json, knip.jsonc, .knip.json, knip.ts, or a knip key in package.json.
Basic Config (knip.json)
{
"$schema": "https://unpkg.com/knip@latest/schema.json",
"entry": ["src/index.ts", "src/main.ts"],
"project": ["src/**/*.ts"],
"ignore": ["**/*.test.ts", "**/*.spec.ts"],
"ignoreDependencies": ["@types/node"]
}
Monorepo Config
{
"$schema": "https://unpkg.com/knip@latest/schema.json",
"workspaces": {
"packages/*": {
"entry": ["src/index.ts"],
"project": ["src/**/*.ts"]
},
"apps/web": {
"entry": ["src/main.tsx", "next.config.{js,ts}"],
"project": ["src/**/*.{ts,tsx}"]
}
}
}
Common Framework Configurations
Next.js:
{
"entry": [
"src/app/**/page.tsx",
"src/app/**/layout.tsx",
"src/app/**/route.ts",
"src/app/**/loading.tsx",
"src/app/**/error.tsx",
"src/app/**/not-found.tsx",
"src/middleware.ts",
"next.config.{js,ts,mjs}"
],
"project": ["src/**/*.{ts,tsx}"]
}
Vite/React:
{
"entry": ["src/main.tsx", "vite.config.ts"],
"project": ["src/**/*.{ts,tsx}"]
}
Express/Node API:
{
"entry": ["src/index.ts", "src/server.ts"],
"project": ["src/**/*.ts"],
"ignoreDependencies": ["@types/express"]
}
Built-in Plugin Support
Knip has built-in plugins for common tools and frameworks. These automatically detect entry points so you don't need to configure them manually:
- Frameworks: Next.js, Remix, Astro, Nuxt, Svelte, Angular, Gatsby
- Build tools: Vite, Webpack, Rollup, esbuild, tsup, Turbopack
- Testing: Jest, Vitest, Mocha, Playwright, Cypress, Storybook
- Linting: ESLint, Prettier, Stylelint, lint-staged, commitlint
- Bundlers/Config: TypeScript, Babel, PostCSS, Tailwind CSS
- CI/CD: GitHub Actions, Husky, Lefthook
- Other: Prisma, Drizzle, GraphQL Codegen, Sentry, MSW
When a plugin detects its config file, it automatically adds the right entry points. Override or extend with explicit config only when needed.
Running Knip
Basic Commands
# Full scan — all issue types
pnpm knip
# Specific reporters
pnpm knip --reporter compact # Condensed output
pnpm knip --reporter json # Machine-readable JSON
pnpm knip --reporter markdown # Markdown table format
# Filter by issue type
pnpm knip --include files # Only unused files
pnpm knip --include dependencies # Only unused deps
pnpm knip --include exports # Only unused exports
pnpm knip --include types # Only unused types
pnpm knip --include duplicates # Only duplicate packages
pnpm knip --include unlisted # Only unlisted deps
# Exclude issue types
pnpm knip --exclude exports # Everything except unused exports
# Production mode (skip devDependencies analysis)
pnpm knip --production
# Strict mode (also flag re-exports and namespace imports as unused)
pnpm knip --strict
# Show which plugins are activated
pnpm knip --debug
# Performance profiling
pnpm knip --performance
Auto-Fix Mode
# Remove unused exports and dependencies automatically
pnpm knip --fix
# Preview what --fix would change (dry run)
pnpm knip --fix --dry-run
# Only fix specific categories
pnpm knip --fix --include exports
pnpm knip --fix --include dependencies
# Remove unused files (moves to trash by default if trash-cli is installed)
pnpm knip --fix --allow-remove-files
Important --fix behavior:
- Removes unused
exportkeywords from declarations - Removes unused dependency entries from
package.json - Does NOT delete files unless
--allow-remove-filesis passed - Does NOT run your package manager's install after removing deps — you must run
pnpm installafter - Always review changes with
git diffafter running--fix
Safe Removal Workflow
Follow this order when cleaning up knip findings to avoid cascading false positives:
Step 1: Fix Unlisted Dependencies First
pnpm knip --include unlisted
# Add any missing packages to package.json
pnpm add <missing-package>
Step 2: Remove Unused Dependencies
pnpm knip --include dependencies --fix
pnpm install # Regenerate lockfile
Step 3: Remove Unused Exports
# Preview first
pnpm knip --include exports --fix --dry-run
# Then apply
pnpm knip --include exports --fix
Step 4: Remove Unused Files
# List unused files
pnpm knip --include files
# Review each file manually before deletion
# Only use --allow-remove-files when confident
Step 5: Verify Nothing Broke
pnpm tsc --noEmit # Type check
pnpm test # Run tests
pnpm build # Verify build
pnpm knip # Re-run to confirm clean
Handling False Positives
Knip may flag things as unused that are actually needed:
Dynamic imports / runtime usage
{
"ignoreDependencies": ["sharp", "pg-native"]
}
Exports consumed by external packages (library authors)
{
"entry": ["src/index.ts!"],
"ignore": ["src/internal/**"]
}
The ! suffix means "include all exports from this entry as used."
Framework magic (decorators, auto-imports, etc.)
Use the appropriate plugin or add explicit entry points.
Per-file export ignore
/** @public */
export function myPublicAPI() {} // knip respects JSDoc @public tag
Or use the @knip tag in comments:
// @knip — used by external consumers
export const API_VERSION = "2.0";
Ignore patterns
{
"ignore": [
"**/*.d.ts",
"**/generated/**",
"scripts/**"
],
"ignoreDependencies": [
"@types/*",
"dotenv"
]
}
Interpreting Results
When presenting knip results:
- Group by severity — unlisted deps and unresolved imports are critical; unused types are informational
- Check before removing exports — they may be part of a public API consumed by other packages
- Cross-reference unused deps — check if they're used in scripts, CI configs, or Dockerfiles that knip doesn't scan
- Unused files — verify they aren't dynamically imported, used as templates, or referenced in config files
- Duplicate packages — these bloat bundles; resolve by aligning versions in
package.jsonor usingpnpm dedupe
Integration with Quality Gate
Knip is included in the quality gate as a WARN-level check. For standalone deep analysis, use the /knip command instead, which provides more granular control and guided cleanup workflows.