Unused Code Detection Tools


Jun 27, 2025

SUPERSEDED

[Development Team]

#frontend #static #analysis #code #quality #dead #code

Context and Problem Statement

As our codebase grows, it becomes increasingly important to identify and remove unused code to maintain a clean, efficient, and maintainable codebase. Unused code, including unused exports, dependencies, and files, can lead to increased bundle size, maintenance overhead, and confusion for developers.

Which tools should we use to detect and manage unused code in our TypeScript/JavaScript application?

Decision Drivers

  • Support for TypeScript
  • Ability to detect different types of unused code (exports, dependencies, files)
  • Integration with our build and CI processes
  • Developer experience and ease of use
  • Accuracy of detection
  • Customizability and configuration options
  • Minimal false positives

Considered Options

  • knip
  • ts-prune
  • ESLint with unused-imports plugin
  • Combination of knip and ts-prune
  • TypeScript compiler with --noUnusedLocals and --noUnusedParameters

Decision Outcome

Chosen option: Combination of knip and ts-prune

We have decided to use both knip and ts-prune for the Newgotiate UI application to provide comprehensive coverage of unused code detection.

Reasoning

  1. Complementary Strengths: knip provides broad coverage for detecting unused dependencies, files, and exports, while ts-prune specializes in identifying unused TypeScript exports with high precision.

  2. TypeScript Support: Both tools have excellent support for TypeScript, which is our primary language.

  3. Integration: Both tools can be easily integrated into our pre-commit hooks and CI/CD pipeline.

  4. Developer Experience: The combination provides clear, actionable feedback to developers about unused code.

  5. Customizability: Both tools offer configuration options to ignore specific files or patterns, allowing us to adapt to our project's specific needs.

Implementation Notes

  • Configuration for ts-prune is stored in .ts-prunerc at the project root
  • We've integrated both tools into our pre-commit hooks via the lint:unused script
  • Custom ignore patterns have been established for generated code and specific files
  • The pre-commit process will fail if unused exports are detected

Consequences

  • Developers need to be aware of and maintain the ignore patterns for both tools
  • We need to ensure proper setup in both development and CI environments
  • We should document common patterns for handling false positives

Pros and Cons of the Options

knip

  • Good, because it provides comprehensive detection of unused dependencies, exports, and files
  • Good, because it has excellent TypeScript support
  • Good, because it integrates well with modern JavaScript/TypeScript projects
  • Good, because it has active community support and documentation
  • Bad, because it may produce some false positives that require configuration to ignore
  • Bad, because it has a more complex configuration compared to simpler tools

ts-prune

  • Good, because it focuses specifically on unused TypeScript exports with high precision
  • Good, because it has a simple, straightforward API
  • Good, because it's lightweight and fast
  • Good, because it integrates easily with CI/CD pipelines
  • Bad, because it only detects unused exports, not other types of unused code
  • Bad, because it requires additional scripting for proper error handling in CI environments

ESLint with unused-imports plugin

  • Good, because it integrates with our existing ESLint setup
  • Good, because it can automatically fix some issues (removing unused imports)
  • Good, because it's part of the linting process developers are already familiar with
  • Bad, because it focuses primarily on imports rather than exports
  • Bad, because it doesn't detect unused dependencies at the package level
  • Bad, because it may require complex configuration for accurate detection

TypeScript compiler flags

  • Good, because it's built into the TypeScript compiler
  • Good, because it doesn't require additional dependencies
  • Good, because it's integrated with the type-checking process
  • Bad, because it only works at the file level during compilation
  • Bad, because it doesn't detect unused dependencies or files
  • Bad, because it can't be easily customized for specific project needs