Dead code — unused components, unexported utility modules, unreachable API routes — imposes a cognitive tax on every developer who reads the codebase. Is this file used? Was it intentionally removed? Should I modify it or ignore it? ISO 25010 maintainability.analysability degrades as dead code accumulates. It also creates false positives in security reviews: an unused API route with no authentication looks like a security gap even if nothing calls it. AI-generated codebases accumulate dead code across sessions as earlier implementations get replaced without cleanup.
Medium because substantial dead code increases cognitive overhead and misleads security reviews, but does not break runtime behavior until a dead module is incorrectly believed to be unreachable and then unexpectedly invoked.
Find unused exports and modules automatically:
npx ts-prune # finds unused TypeScript exports
# or
npx knip # comprehensive dead code detection
Before deleting, confirm with git log that code wasn't recently added and is genuinely unreachable. Prevent accumulation with:
"no-unused-vars": ["warn", { "vars": "all", "args": "after-used" }]
Delete confirmed dead code and commit with a descriptive message — git history preserves it if recovery is ever needed.
ID: code-maintainability.code-hygiene.no-dead-code
Severity: medium
What to look for: Look for code that is defined but never called or imported. Common patterns:
lib/ or utils/ that are never imported anywhereFocus on non-trivial code (>10 lines). Single unused utility functions are acceptable; entire unused modules are not. Check if eslint-plugin-unused-imports or the no-unused-vars rule is configured to catch this.
Pass criteria: Count all exported functions, components, and modules in src/. No entire unused modules or components found. No more than 2 minor unused exports are acceptable if an ESLint rule would catch them. Report the count: "X of Y exports are actively used."
Fail criteria: Two or more substantial code units (components, utility modules, or API routes with over 10 lines) are defined but never imported or called anywhere.
Skip (N/A) when: The project has fewer than 10 source files — not enough for meaningful dead code analysis. Signal: fewer than 10 distinct source files.
Detail on fail: "Dead code found: components/OldDashboard.tsx (80 lines, never imported), lib/legacy-auth.ts (120 lines, all exports unused), app/api/v1/deprecated-endpoint/route.ts (never called from frontend or tests)." or "15 exported functions in lib/utils.ts have no importers across the codebase."
Remediation: Dead code imposes a mental tax — developers must read and understand code that does nothing. It also creates false positives in security reviews and makes refactoring riskier (is this code truly unused, or did I miss an import?).
To find unused exports automatically:
npx ts-prune # finds unused TypeScript exports
# or
npx knip # comprehensive dead code detection
Remove confirmed dead code and add an ESLint rule to prevent accumulation:
"no-unused-vars": ["warn", { "vars": "all", "args": "after-used" }]
Before removing, confirm with git history that the code wasn't recently added and is actually unreachable (not just indirectly referenced through dynamic imports).