knip-dead-code
Run Knip against a JS/TS project to detect unused files, unused dependencies, unused exports, and unused class/enum members. Scoped to production code; tests are entry-point-aware via Knip's framework plugins. Use after a feature or route is deleted and the project still compiles, or when `package.json` has accumulated dependencies nobody can account for.
Install with skills.sh (any agent)
npx skills add testland/qa --skill knip-dead-codeknip-dead-code
Knip detects unused files, dependencies, exports, types, enum members, and class members in JS/TS projects per the Knip docs (opens in new window). Requires Node ≥ 20.19.0 (or Bun).
When to use
Step 1 - Install
# Recommended: setup wizard (auto-detects framework)
npm init @knip/config
# Manual
npm install -D knip typescript @types/nodeAdd package.json script:
{
"scripts": {
"knip": "knip"
}
}Per the Knip docs (opens in new window).
Step 2 - Configure entry points
knip.json:
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"entry": [
"src/index.ts",
"src/cli.ts",
"scripts/**/*.ts"
],
"project": ["src/**/*.{ts,tsx}"],
"ignore": ["src/**/*.generated.ts"],
"ignoreDependencies": [
"@types/node"
],
"ignoreExportsUsedInFile": true
}Or knip.config.ts for typed config.
Entry vs project: entry = files Knip starts walking the import graph from. project = the universe of files it considers reachable. Anything in project not reached from entry is unused.
Step 3 - First run
npx knipExit code: 0 if clean, non-zero if unused items found. Shows:
Unused files (3)
Unused dependencies (2)
Unused exports (12)
Unused exported types (4)
Unused exported enum members (1)Step 4 - Use framework plugins
For framework-aware scanning, enable plugins (auto-detected by npm init @knip/config):
{
"next": {
"entry": ["next.config.{js,ts,cjs,mjs}", "app/**/page.{js,ts,tsx}"]
},
"playwright": {
"config": "playwright.config.ts",
"entry": ["e2e/**/*.spec.ts"]
}
}Plugin list (Next.js, Remix, Astro, Vite, Storybook, Playwright, Jest, etc.) - see the Knip plugins page (opens in new window).
Step 5 - Limit output during cleanup
# Show only top 5 of each issue type - useful when first adopting
npx knip --max-show-issues 5Per the Knip docs (opens in new window) for overwhelming output.
Step 6 - CI gate
# GitHub Actions
- name: Knip dead-code check
run: npx knipFails build on any new dead code. For brownfield rollout, baseline existing dead code first:
# Snapshot current findings; CI only fails on additions
npx knip --no-exit-code > knip-baseline.txtStep 7 - Per-issue triage
| Reported as | True positive? | Action |
|---|---|---|
| Unused file | Usually yes | Delete |
| Unused dependency | Usually yes | npm uninstall |
| Unused export | Sometimes (public API) | Mark with JSDoc @public + tags: ["public"] config |
| Unused enum member | Usually yes | Delete |
| Unused class member | Sometimes (public API) | Same as unused export |
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Run without entry points | Everything looks orphaned | Always set entry (Step 2) |
| Treat "unused export" as "delete now" | Public library APIs flag as unused | Use tags: ["public"] for library packages |
| Skip framework plugins | Next.js page files look orphaned (Knip doesn't know they're routes) | Enable plugin (Step 4) |
| Block PRs from day 1 in brownfield | Hundreds of pre-existing unused; team disables tool | Baseline first (Step 6 alt path) |
| Auto-fix mode on first run | --fix deletes legitimate unused public exports | Manual review first; --fix after baseline clean |
Limitations
References
Related skills
codeclimate-config
Configure Code Climate Quality (now Qlty) for repository-wide quality gates - duplication, complexity, similar-code, exclude_patterns. Covers both legacy `.codeclimate.yml` (Code Climate Velocity / GitHub integration) and the new `.qlty/qlty.toml` per the Qlty platform migration. Use when a repo needs duplication and complexity thresholds enforced on PRs, or when an existing `.codeclimate.yml` must be migrated to Qlty without losing its plugin and exclude settings.
lizard-complexity
Run Lizard against production source to enforce per-function cyclomatic complexity (CCN), NLOC, and parameter-count thresholds - language-agnostic (30+ languages). Scoped to production code via `-x"./tests/*"`; test complexity is reviewed separately. Use when a codebase spans several languages and needs one complexity gate across all of them, or when a function has grown unreviewable and the team wants a numeric threshold in CI.
madge-deps
Run Madge against a JS/TS production source tree to detect circular dependencies, find orphan modules, and visualize the module graph. Scoped to production code via `excludeRegExp` for test files. Use when a build compiles but throws `Cannot read property X of undefined` on a module that is clearly imported, or when a repo needs a CI gate that blocks new import cycles.
sonarqube-maintainability-gate
Run SonarQube/SonarCloud against production code to surface Code Smells, Bugs, and Maintainability ratings - the maintainability lens rather than the security lens. Production-only scope via sonar.exclusions; test code is reviewed separately. Use when a team wants maintainability and technical-debt ratings gating PRs, or when an existing SonarQube project reports numbers nobody has tied to a quality gate.