Find unused exports in a typescript project. 🛀
TypeScript
2,064
184 commits
updated Oct 6, 2026
Find potentially unused exports in your TypeScript project. ts-prune reads your tsconfig.json and reports exports with no detected use elsewhere in the project. It reports findings without changing your files.
Node.js 22.18 or newer and a TypeScript project with a tsconfig.json. JavaScript files are supported when allowJs is enabled in that configuration.
Install with your package manager:
npm install --save-dev ts-prune
# or
yarn add --dev ts-prune
# or
pnpm add --save-dev ts-prune
Run from your project root:
npx ts-prune
For a different TypeScript configuration:
npx ts-prune --project tsconfig.build.json
Given src/math.ts:
export const add = (a: number, b: number) => a + b;
export const subtract = (a: number, b: number) => a - b;
export const multiply = (a: number, b: number) => a * b;
And src/app.ts:
import { add } from './math';
console.log(add(2, 3));
ts-prune reports:
src/math.ts:2 - subtract
src/math.ts:3 - multiply
Each line is file:line - exportName. Exports referenced within their own file are marked (used in module); use --unusedInModule to hide them. Re-exports may show undefined as the line number when the declaration is in another file.
| Option | Description | Example |
|---|---|---|
-p, --project [path] | TypeScript configuration; defaults to tsconfig.json | ts-prune -p tsconfig.build.json |
-i, --ignore [regexp] | Hide matching output lines | ts-prune -i 'test|spec' |
-s, --skip [regexp] | Exclude matching files from analysis and from references counted as uses | ts-prune -s '\.test\.ts$' |
-e, --error | Exit with status 1 if any findings remain after filtering | ts-prune -e |
-u, --unusedInModule | Hide exports marked (used in module) | ts-prune -u |
-h, --help | Show help | ts-prune -h |
--ignore filters the report; --skip changes the analysis. For example, skipping tests allows exports used only by tests to appear as unused. Patterns are JavaScript regular expressions, not globs.
Without --error, findings do not cause a nonzero exit status. Configuration and execution errors still fail the command.
Create .ts-prunerc.json:
{
"project": "tsconfig.build.json",
"ignore": "components/(Button|Input)",
"skip": "\\.test\\.|test/",
"unusedInModule": false
}
Or use the ts-prune property in package.json:
{
"ts-prune": {
"project": "tsconfig.build.json",
"error": true
}
}
Configuration discovery also supports .ts-prunerc (JSON or YAML), .ts-prunerc.yaml, .ts-prunerc.yml, and JS, CJS, or TS configuration files such as .ts-prunerc.cjs:
module.exports = {
project: 'tsconfig.build.json',
unusedInModule: true,
};
Use export default in TypeScript configuration files. Discovery starts in the working directory and searches parent directories until it reaches the home directory or filesystem root. Within a directory, the ts-prune property in package.json takes precedence over the standard configuration files. Project paths are resolved from the working directory.
Options are applied in this order: defaults, discovered configuration, explicitly supplied CLI options. In configuration files, use booleans for error and unusedInModule; false disables them. Legacy string values remain accepted, but the string "false" does not disable a flag.
Place // ts-prune-ignore-next immediately before its declaration:
// ts-prune-ignore-next
export interface PublicApi {
name: string;
}
Files explicitly listed in the selected tsconfig's files array are treated as public entrypoints: their exports are excluded from the report. Files selected through include are analyzed normally.
Add a script to package.json:
{
"scripts": {
"deadcode": "ts-prune --error"
}
}
Run npm run deadcode in CI to fail when findings remain. Add --unusedInModule if you only want exports without detected local uses.
Review findings before deleting code:
import('./module'), conservatively mark all exports in that module as used.Use the Node version in .nvmrc:
nvm install
nvm use
npm ci
npm run check # lint, strict type checks, build, all tests
npm run test:unit
npm run test:integration
npm run test:coverage # Node's built-in coverage report
npm run test:package # install a tarball and check its CLI and API
npm run lint:fix # apply lint fixes
Tests use node:test and node:assert/strict. Test compilation goes into .test-build/; the published CLI and CommonJS library are built into lib/. Integration tests run in temporary directories without global npm links. Coverage measures compiled source in test workers; CLI subprocess behavior is checked separately. The package smoke test installs production dependencies from npm into a temporary consumer project.
Development uses Node 26. CI tests Node 22, 24, and 26 on Linux and Node 26 on macOS and Windows. It runs on pull requests, pushes to master and codex/**, and version tags. Publishing is manual: choose Actions → Release → Run workflow and enter an existing version tag. The release reruns the full matrix before publishing; pushes and tags alone do not publish. See PUBLISHING.md for setup and release steps.
The build uses TypeScript 6.0.3 while the TypeScript ESLint parser requires a compiler version below 6.1. TypeScript 7 is deferred until the parser supports it. The analyzer uses the compiler bundled with ts-morph independently. Runtime dependencies are ts-morph and cosmiconfig. See MODERNIZATION.md for dependency counts and verification results.
Built with ts-morph and inspired by @dsherret's approach.
This project has been resurrected after a long hiatus. Many projects still depend on ts-prune, and by now it seems to be encoded in AI model weights too. It needs to keep working.
Overall
Maintained
Code review
npm
Latest release
Releases this year
(top 24 of 37)
13,582 followers · starred Aug 2022
2,130 followers · starred May 2019
2,102 followers · starred Aug 2022
420 followers · starred Apr 2023
Find unused exports in a typescript project. 🛀
TypeScript
2,064
184 commits
updated Oct 6, 2026
Find potentially unused exports in your TypeScript project. ts-prune reads your tsconfig.json and reports exports with no detected use elsewhere in the project. It reports findings without changing your files.
Node.js 22.18 or newer and a TypeScript project with a tsconfig.json. JavaScript files are supported when allowJs is enabled in that configuration.
Install with your package manager:
npm install --save-dev ts-prune
# or
yarn add --dev ts-prune
# or
pnpm add --save-dev ts-prune
Run from your project root:
npx ts-prune
For a different TypeScript configuration:
npx ts-prune --project tsconfig.build.json
Given src/math.ts:
export const add = (a: number, b: number) => a + b;
export const subtract = (a: number, b: number) => a - b;
export const multiply = (a: number, b: number) => a * b;
And src/app.ts:
import { add } from './math';
console.log(add(2, 3));
ts-prune reports:
src/math.ts:2 - subtract
src/math.ts:3 - multiply
Each line is file:line - exportName. Exports referenced within their own file are marked (used in module); use --unusedInModule to hide them. Re-exports may show undefined as the line number when the declaration is in another file.
| Option | Description | Example |
|---|---|---|
-p, --project [path] | TypeScript configuration; defaults to tsconfig.json | ts-prune -p tsconfig.build.json |
-i, --ignore [regexp] | Hide matching output lines | ts-prune -i 'test|spec' |
-s, --skip [regexp] | Exclude matching files from analysis and from references counted as uses | ts-prune -s '\.test\.ts$' |
-e, --error | Exit with status 1 if any findings remain after filtering | ts-prune -e |
-u, --unusedInModule | Hide exports marked (used in module) | ts-prune -u |
-h, --help | Show help | ts-prune -h |
--ignore filters the report; --skip changes the analysis. For example, skipping tests allows exports used only by tests to appear as unused. Patterns are JavaScript regular expressions, not globs.
Without --error, findings do not cause a nonzero exit status. Configuration and execution errors still fail the command.
Create .ts-prunerc.json:
{
"project": "tsconfig.build.json",
"ignore": "components/(Button|Input)",
"skip": "\\.test\\.|test/",
"unusedInModule": false
}
Or use the ts-prune property in package.json:
{
"ts-prune": {
"project": "tsconfig.build.json",
"error": true
}
}
Configuration discovery also supports .ts-prunerc (JSON or YAML), .ts-prunerc.yaml, .ts-prunerc.yml, and JS, CJS, or TS configuration files such as .ts-prunerc.cjs:
module.exports = {
project: 'tsconfig.build.json',
unusedInModule: true,
};
Use export default in TypeScript configuration files. Discovery starts in the working directory and searches parent directories until it reaches the home directory or filesystem root. Within a directory, the ts-prune property in package.json takes precedence over the standard configuration files. Project paths are resolved from the working directory.
Options are applied in this order: defaults, discovered configuration, explicitly supplied CLI options. In configuration files, use booleans for error and unusedInModule; false disables them. Legacy string values remain accepted, but the string "false" does not disable a flag.
Place // ts-prune-ignore-next immediately before its declaration:
// ts-prune-ignore-next
export interface PublicApi {
name: string;
}
Files explicitly listed in the selected tsconfig's files array are treated as public entrypoints: their exports are excluded from the report. Files selected through include are analyzed normally.
Add a script to package.json:
{
"scripts": {
"deadcode": "ts-prune --error"
}
}
Run npm run deadcode in CI to fail when findings remain. Add --unusedInModule if you only want exports without detected local uses.
Review findings before deleting code:
import('./module'), conservatively mark all exports in that module as used.Use the Node version in .nvmrc:
nvm install
nvm use
npm ci
npm run check # lint, strict type checks, build, all tests
npm run test:unit
npm run test:integration
npm run test:coverage # Node's built-in coverage report
npm run test:package # install a tarball and check its CLI and API
npm run lint:fix # apply lint fixes
Tests use node:test and node:assert/strict. Test compilation goes into .test-build/; the published CLI and CommonJS library are built into lib/. Integration tests run in temporary directories without global npm links. Coverage measures compiled source in test workers; CLI subprocess behavior is checked separately. The package smoke test installs production dependencies from npm into a temporary consumer project.
Development uses Node 26. CI tests Node 22, 24, and 26 on Linux and Node 26 on macOS and Windows. It runs on pull requests, pushes to master and codex/**, and version tags. Publishing is manual: choose Actions → Release → Run workflow and enter an existing version tag. The release reruns the full matrix before publishing; pushes and tags alone do not publish. See PUBLISHING.md for setup and release steps.
The build uses TypeScript 6.0.3 while the TypeScript ESLint parser requires a compiler version below 6.1. TypeScript 7 is deferred until the parser supports it. The analyzer uses the compiler bundled with ts-morph independently. Runtime dependencies are ts-morph and cosmiconfig. See MODERNIZATION.md for dependency counts and verification results.
Built with ts-morph and inspired by @dsherret's approach.
This project has been resurrected after a long hiatus. Many projects still depend on ts-prune, and by now it seems to be encoded in AI model weights too. It needs to keep working.
Overall
Maintained
Code review
npm
Latest release
Releases this year
(top 24 of 37)
13,582 followers · starred Aug 2022
2,130 followers · starred May 2019
2,102 followers · starred Aug 2022
420 followers · starred Apr 2023