Knip: The Ultimate Dead Code Detector for JavaScript & TypeScript Projects

Published: (December 23, 2025 at 02:51 PM EST)
5 min read
Source: Dev.to

Source: Dev.to

The Problem: Dead Code is Everywhere

Every mature codebase has a dirty secret: dead code.
The utility function someone wrote “just in case.”
The component from a feature that was scrapped.
The npm package installed for a spike that never went anywhere.

ESLint can catch unused variables and imports within a file, but what about:

  • Files that are never imported anywhere?
  • Exported functions that no one uses?
  • Dependencies in package.json you forgot to remove?
  • Types and interfaces defined but never referenced?

This is where Knip comes in.

What is Knip?

Knip (Dutch for “cut”) is a powerful static‑analysis tool that finds unused files, dependencies, and exports in your JavaScript/TypeScript projects. Think of it as Marie Kondo for your codebase — if code doesn’t spark joy (or get used), it’s gotta go.

What Knip Detects

CategoryDescription
🗂️ Unused FilesSource files that aren’t imported anywhere
📦 Unused DependenciesPackages in package.json that aren’t used
📤 Unused ExportsFunctions, classes, types exported but never imported
🔧 Unused Dev DependenciesDev packages that aren’t needed
Unlisted DependenciesPackages used in code but missing from package.json
🔗 Unresolved ImportsImports pointing to non‑existent modules

Knip report example

Getting Started

Installation

# npm
npm install -D knip

# yarn
yarn add -D knip

# pnpm
pnpm add -D knip

Basic Usage

npx knip

That’s it! Knip will analyze your project and output all the unused code it finds.

Configuration

For most projects, Knip works out of the box. For complex setups (monorepos, custom entry points, etc.) you’ll want a config file.

Create knip.json in your project root:

{
  "$schema": "https://unpkg.com/knip@5/schema.json",
  "entry": ["src/index.ts", "src/App.tsx"],
  "project": ["src/**/*.{ts,tsx}"],
  "ignore": [
    "**/__tests__/**",
    "**/__mocks__/**",
    "**/node_modules/**"
  ],
  "ignoreDependencies": [
    "prettier",
    "husky"
  ],
  "ignoreExportsUsedInFile": true
}

Key Configuration Options

OptionDescription
entryEntry‑point files where Knip starts tracing
projectFiles to analyze
ignoreFiles/patterns to skip
ignoreDependenciesDependencies to skip (useful for config‑only packages)
ignoreExportsUsedInFileDon’t report exports used only in the same file

React Native Example

{
  "$schema": "https://unpkg.com/knip@5/schema.json",
  "entry": ["src/App.tsx", "index.js"],
  "project": ["src/**/*.{ts,tsx}"],
  "ignore": [
    "**/__tests__/**",
    "**/__mocks__/**",
    "android/**",
    "ios/**"
  ],
  "ignoreDependencies": [
    "@react-native/metro-config",
    "@react-native/typescript-config",
    "@react-native/babel-preset",
    "patch-package",
    "husky",
    "reactotron-react-native"
  ],
  "ignoreExportsUsedInFile": true
}

Real‑World Results

Running Knip on a production React Native app produced:

Unused files (73)
src/components/map/index.tsx
src/components/views/NotificationMenuButton.tsx
src/models/requests/auth/authRequests.ts
src/utils/helpers/contactHelper.ts
... and 69 more

Unused dependencies (1)
@react-native-firebase/perf

Unused devDependencies (4)
@babel/preset-env
@testing-library/jest-native
@types/react-native-get-random-values
eslint-plugin-react-you-might-not-need-an-effect

Unlisted dependencies (2)
credit-card-type  src/features/paymentMethods/addNewCard/index.tsx

Unused exports (74)
translations        src/config/localization/languages.ts
defaultAddressForm src/features/addressBook/addressTypes.ts
... and more

73 unused files! That’s potentially thousands of lines of dead code that:

  • Increase bundle size
  • Confuse new developers
  • Create maintenance burden
  • Appear in search results, wasting time

Integrating with Your Workflow

NPM Scripts

Add these to your package.json:

{
  "scripts": {
    "knip:check": "knip",
    "knip:fix": "knip --fix"
  }
}

CI/CD Integration

# .github/workflows/code-quality.yml
name: Code Quality

on: [push, pull_request]

jobs:
  knip:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx knip

Pre‑commit Hook (with Husky)

# .husky/pre-commit
npx knip --no-exit-code

Auto‑Fixing with --fix

npx knip --fix

⚠️ Warning: This modifies your files! Always review changes and have version control ready.

What --fix can do:

  • ✅ Remove unused exports
  • ✅ Remove unused dependencies from package.json
  • ❌ Cannot delete unused files (too risky)

Tips & Best Practices

  1. Start with --include to focus – If you’re overwhelmed by results, limit the analysis to a specific folder or category first.
  2. Run Knip regularly (e.g., in CI) to keep dead code from accumulating.
  3. Pair Knip with code‑review checklists: “No new unused imports/files.”
  4. After fixing, commit the changes and let the team know the cleanup is complete.

By adopting Knip, you’ll keep your codebase lean, improve developer experience, and ship smaller, faster bundles. Happy cleaning!

Usage Tips for Knip

1. Include Specific Checks

# Only check for unused files
npx knip --include files

# Only check dependencies
npx knip --include dependencies

# Check multiple categories
npx knip --include files,exports

2. Choose an Output Reporter

# JSON output (great for tooling)
npx knip --reporter json

# Markdown (for documentation)
npx knip --reporter markdown

3. Ignore Known False Positives

Some code is used dynamically or through conventions that Knip can’t detect:

{
  "ignore": [
    "src/generated/**",
    "**/*.stories.tsx"
  ],
  "ignoreDependencies": [
    "tsconfig-paths"
  ]
}

4. Handle Barrel Exports

If you use barrel files (index.ts re‑exporting everything), Knip might report false positives. Enable:

{
  "ignoreExportsUsedInFile": true
}

5. Framework‑Specific Plugins

Knip has built‑in support for many frameworks:

{
  "next": {
    "entry": ["pages/**/*.tsx", "app/**/*.tsx"]
  },
  "jest": {
    "config": ["jest.config.js"]
  },
  "storybook": {
    "entry": [".storybook/main.ts"]
  }
}

Knip vs. Other Tools

ToolUnused FilesUnused ExportsUnused DepsAuto‑fix
Knip
ESLintPartial
ts‑prune
depcheck
unimported

Knip is the all‑in‑one solution that replaces multiple tools.

Common Issues & Solutions

“I’m getting too many false positives!”

  • Verify if the code is dynamically imported.
  • Add patterns to ignore in the config.
  • Use ignoreDependencies for config‑only packages.
  • Enable ignoreExportsUsedInFile.

“Knip is slow on my large monorepo”

{
  "ignore": [
    "**/dist/**",
    "**/build/**",
    "**/coverage/**"
  ]
}

“It’s not finding my entry points”

Explicitly define them:

{
  "entry": [
    "src/index.ts",
    "src/cli.ts",
    "scripts/*.ts"
  ]
}

Conclusion

Dead code is technical debt that compounds over time. Every unused file is:

  • Bytes shipped to users
  • Cognitive overhead for developers
  • A potential security vulnerability
  • Wasted CI/CD minutes

Knip gives you visibility into what’s actually being used in your codebase. Run it once—you might be shocked by what you find. Run it regularly, and keep your codebase lean and maintainable.

# Try it now
npx knip

Resources

Did Knip help clean up your codebase? Share your results in the comments! I’d love to hear how much dead code you found. 🔪

Tags: javascript, typescript, webdev, productivity

Back to Blog

Related posts

Read more »

Rust got 'pub' wrong

!Cover image for Rust got 'pub' wronghttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s...