Start with automated detection, then review findings manually
You can find unused code in a JavaScript project by combining static analysis, dependency checks, and gradual removal with mandatory test and build runs after each change. A single tool cannot detect every case: unused exports, files, npm packages, and local variables require different checks.
1. Check unused variables and imports
The first level of verification is a linter. For projects with ESLint, use rules that detect unused local variables and imports.
Make sure the no-unused-vars rule is enabled in the ESLint configuration:
{
"rules": {
"no-unused-vars": "error"
}
}
Then run the project check:
npx eslint .
This analysis helps find code such as declared variables that are never read or imports that are no longer needed after changes.
2. Find unused exports and files
A linter usually cannot determine that an entire module is no longer imported anywhere. Specialized analyzers are better suited for this task. One commonly used option for JavaScript and TypeScript projects is Knip.
Install it in the project as a development dependency:
npm install --save-dev knip
Run the analysis:
npx knip
The tool can show unused files, exports, and dependencies. Before deleting each detected item, check whether it is used through dynamic imports, plugin registration, configuration files, or an external package interface.
Do not automatically remove detected code. Static analysis does not always see calls through strings, runtime module loading, or usage through external systems.
3. Check bundler settings
Modern bundlers can remove unreachable code during the build process, but the presence of tree shaking does not mean that the source project contains no unnecessary files or dependencies.
Check that the project correctly describes its modules. For example, in npm libraries the sideEffects field in package.json affects the ability of some bundlers to safely remove unused code.
{
"sideEffects": false
}
Use this value only if files truly do not contain side effects during import. If a module performs actions immediately after loading, such as registering handlers or changing global state, an incorrect setting can change application behavior.
4. Find unused npm dependencies
Removed JavaScript code often leaves behind packages that are no longer required. Check dependencies separately from the source code.
First, view the current dependency list:
npm ls --depth=0
Then use a dependency analyzer, such as Knip, to find packages that are not used in the source code. Verify detected dependencies before removing them: some packages are only needed for build scripts, testing, or command-line tools.
5. Check TypeScript projects with additional settings
If the project uses TypeScript, the compiler can additionally detect unused declarations. Enable the relevant options in tsconfig.json:
{
"compilerOptions": {
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
After changing the configuration, run the type check:
npx tsc --noEmit
These options are suitable for controlling source code during development. In some projects, enabling them requires gradual cleanup of existing warnings.
6. Look for dead code that tools cannot detect
Some unused code cannot be reliably identified through static analysis alone. Manually check the following areas:
- old interface components after a redesign;
- utilities left after replacing a library;
- event handlers that are no longer connected;
- experimental features and temporary flags;
- old configurations and unused scripts.
Searching through imports and file names is useful for finding candidates. For example, if you find a file named legacyParser.js, first check all places where it is imported:
grep -R "legacyParser" src
The command depends on the operating system and shell. On Windows, a similar search can be performed using PowerShell or a code editor.
7. Remove code in safe iterations
- Create a separate commit before cleanup.
- Remove small groups of related files.
- Run tests after every significant deletion.
- Check the production build if the project uses one.
- Compare the final bundle size only after completing a series of changes.
A minimal verification cycle may look like this:
npx eslint .
npx tsc --noEmit
npm test
npm run build
Test and build command names depend on the specific project and should match the scripts defined in package.json.
Common mistakes when searching for unused code
| Mistake | Why it is a problem | How to fix it |
|---|---|---|
| Removing all warnings without verification | Tools may not detect dynamic usage | Check detected locations before removal |
| Checking only variables | Entire files and dependencies may remain unnecessary | Use export and package analysis |
| Removing old APIs without finding consumers | Code may be used by external applications | Check public project interfaces |
| Large cleanup in a single commit | It is difficult to find the cause of an error | Make smaller changes |
Final checklist
- Enable checking of unused variables through ESLint.
- Check unused files, exports, and dependencies with a specialized analyzer.
- Enable compiler checks for TypeScript when needed.
- Check dynamic imports, plugins, and external integration points.
- Remove code through small changes with test and build verification.