A Node.js CLI and equivalent JS API to find unused ECMAScript module exports in a project.
To achieve this the whole project is analyzed at once, something ESLint can’t do as it lints files in isolation.
- The
npx find-unused-exports
script is handy for finding redundant code to remove in legacy projects. - Use the CLI command
find-unused-exports
in package test scripts, so that CI can prevent the addition of redundant code.
To install find-unused-exports
with npm, run:
npm install find-unused-exports --save-dev
Then, either use the CLI command find-unused-exports
or import and use the function findUnusedExports
.
.gitignore
files are used to ignore whole files or directories. This is useful for ignoring:
- Third party modules, e.g.
node_modules
. - Compiled files, e.g.
.next
ordist
.
Special comments can be used anywhere in a module to ignore all or specific unused exports. This is useful for ignoring intentionally unused exports intended to be imported from external code, e.g.
- For published packages, the public exports.
- For Next.js projects, the
default
exports inpages
directory modules.
How to ignore all unused exports:
// ignore unused exports
export const a = true;
export default true;
How to ignore specific unused exports:
// ignore unused exports b, default
export const a = true;
export const b = true;
export default true;
Multiple comments can be used:
// ignore unused exports a
export const a = true;
// ignore unused exports b
export const b = true;
Comments are case-insensitive, except for the export names:
// iGnOrE UnUsEd eXpOrTs default
Line or block comments can be used:
/* ignore unused exports */
Supported runtime environments:
- Node.js versions
^18.18.0 || ^20.9.0 || >=22.0.0
.
Projects must configure TypeScript to use types from the ECMAScript modules that have a // @ts-check
comment:
compilerOptions.allowJs
should betrue
.compilerOptions.maxNodeModuleJsDepth
should be reasonably large, e.g.10
.compilerOptions.module
should be"node16"
or"nodenext"
.
Finds unused ECMAScript module exports in a project. If some are found, it reports them to stderr
and exits with a 1
error status. .gitignore
files are used to ignore files.
It implements the function findUnusedExports
.
Argument | Default | Description |
---|---|---|
--import-map |
"{}" |
JSON import map that’s relative to the current working directory. |
--module-glob |
"**/{!(*.d).mts,!(*.d).cts,!(*.d).ts,*.{mjs,cjs,js,jsx,tsx}}" |
Module file glob pattern. |
--resolve-file-extensions |
File extensions (without the leading . , multiple separated with , in preference order) to automatically resolve in extensionless import specifiers. Import specifier file extensions are mandatory in Node.js; if your project resolves extensionless imports at build time (e.g. Next.js, via webpack) mjs,js might be appropriate. |
|
--resolve-index-files |
Should directory index files be automatically resolved in extensionless import specifiers. Node.js doesn’t do this by default; if your project resolves extensionless imports at build time (e.g. Next.js, via webpack) this argument might be appropriate. This argument only works if the argument --resolve-file-extensions is used. |
Using npx
in a standard Node.js project:
npx find-unused-exports
Using npx
in a typical webpack project that has ESM in .js
files, extensionless import specifiers, and index.js
files:
npx find-unused-exports --module-glob "**/*.js" --resolve-file-extensions js --resolve-index-files
Using npx
in a project with an import map in a file import-map.json
:
npx find-unused-exports --import-map "$(cat import-map.json)"
package.json
scripts for a project that also uses eslint
and prettier
:
{
"scripts": {
"prettier": "prettier -c .",
"eslint": "eslint",
"find-unused-exports": "find-unused-exports",
"test": "npm run prettier && npm run eslint && npm run find-unused-exports",
"prepublishOnly": "npm test"
}
}
The npm package find-unused-exports
features optimal JavaScript module design. It doesn’t have a main index module, so use deep imports from the ECMAScript modules that are exported via the package.json
field exports
: