Knip finds unused files, dependencies, exports, and types in JavaScript/TypeScript projects. Plugin system for frameworks (React, Next.js, Vite), test runners (Vitest, Jest), and build tools. TRIGGER WHEN: cleaning up codebases, optimizing bundle size, or enforcing strict dependency hygiene in CI. DO NOT TRIGGER WHEN: the task is outside the specific scope of this component.
npx claudepluginhub acaprino/alfio-claude-plugins --plugin typescript-developmentThis skill uses the workspace's default tool permissions.
Knip is a comprehensive tool for finding unused code, dependencies, and exports in JavaScript and TypeScript projects. It helps maintain clean codebases and catch dead code before it accumulates.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
Knip is a comprehensive tool for finding unused code, dependencies, and exports in JavaScript and TypeScript projects. It helps maintain clean codebases and catch dead code before it accumulates.
What is Knip?
Key Capabilities
Examples below use
npx. Equivalent commands work withbun/bunxoryarn/yarn dlx.
# Project-local (recommended)
npm install --save-dev knip
# Verify installation
npx knip --version
# Run Knip (scans entire project)
npx knip
# Show only unused dependencies
npx knip --dependencies
# Show only unused exports
npx knip --exports
# Show only unused files
npx knip --files
# Production mode (only check production dependencies)
npx knip --production
# Exclude specific issue types
npx knip --exclude-exports-used-in-file
# Output JSON (for CI)
npx knip --reporter json
# Debug mode (show configuration)
npx knip --debug
Knip automatically detects:
main, exports, bin)No configuration needed for standard projects.
{
"$schema": "https://unpkg.com/knip@latest/schema.json",
"entry": ["src/index.ts", "src/cli.ts"],
"project": ["src/**/*.ts"],
"ignore": ["**/*.test.ts", "scripts/**"],
"ignoreDependencies": ["@types/*"],
"ignoreBinaries": ["npm-check-updates"]
}
// knip.ts
import type { KnipConfig } from 'knip';
const config: KnipConfig = {
entry: ['src/index.ts', 'src/cli.ts'],
project: ['src/**/*.ts', 'scripts/**/*.ts'],
ignore: ['**/*.test.ts', '**/*.spec.ts', 'tmp/**'],
ignoreDependencies: [
'@types/*', // Type definitions
'typescript', // Always needed
],
ignoreExportsUsedInFile: true,
ignoreWorkspaces: ['packages/legacy/**'],
};
export default config;
// knip.ts
import type { KnipConfig } from 'knip';
const config: KnipConfig = {
// Entry points
entry: [
'src/index.ts',
'src/cli.ts',
'scripts/**/*.ts', // Include scripts
],
// Project files
project: ['src/**/*.{ts,tsx}', 'scripts/**/*.ts'],
// Ignore patterns
ignore: [
'**/*.test.ts',
'**/*.spec.ts',
'**/__tests__/**',
'**/__mocks__/**',
'dist/**',
'build/**',
'coverage/**',
'.next/**',
],
// Dependencies to ignore
ignoreDependencies: [
'@types/*', // Type definitions used implicitly
'typescript', // Always needed for TS projects
'tslib', // TypeScript helper library
'@biomejs/biome', // Used via CLI
'prettier', // Used via CLI
],
// Binaries to ignore (used in package.json scripts)
ignoreBinaries: ['npm-check-updates', 'semantic-release'],
// Ignore exports used in the same file
ignoreExportsUsedInFile: true,
// Workspace configuration (for monorepos)
workspaces: {
'.': {
entry: ['src/index.ts'],
},
'packages/*': {
entry: ['src/index.ts', 'src/cli.ts'],
},
},
};
export default config;
Knip automatically detects and configures plugins for popular tools:
| Framework | Auto-detected | Entry Points |
|---|---|---|
| Next.js | next.config.js | pages/, app/, middleware.ts |
| Vite | vite.config.ts | index.html, config plugins |
| Remix | remix.config.js | app/root.tsx, app/entry.* |
| Astro | astro.config.mjs | src/pages/, config integrations |
| SvelteKit | svelte.config.js | src/routes/, src/app.html |
| Nuxt | nuxt.config.ts | app.vue, pages/, layouts/ |
| Tool | Auto-detected | Entry Points |
|---|---|---|
| Vitest | vitest.config.ts | **/*.test.ts, config files |
| Jest | jest.config.js | **/*.test.js, setup files |
| Playwright | playwright.config.ts | tests/**/*.spec.ts |
| Cypress | cypress.config.ts | cypress/e2e/**/*.cy.ts |
| Tool | Auto-detected | Entry Points |
|---|---|---|
| TypeScript | tsconfig.json | Files in include |
| ESLint | .eslintrc.js | Config files, plugins |
| PostCSS | postcss.config.js | Config plugins |
| Tailwind | tailwind.config.js | Config plugins, content files |
// knip.ts
const config: KnipConfig = {
// Disable specific plugins
eslint: false,
prettier: false,
// Override plugin config
vitest: {
entry: ['vitest.config.ts', 'test/setup.ts'],
config: ['vitest.config.ts'],
},
next: {
entry: [
'next.config.js',
'pages/**/*.tsx',
'app/**/*.tsx',
'middleware.ts',
'instrumentation.ts',
],
},
};
// knip.ts
const config: KnipConfig = {
// Ignore entire directories
ignore: ['legacy/**', 'vendor/**'],
// Ignore specific dependencies
ignoreDependencies: [
'@types/*',
'some-peer-dependency',
],
// Ignore specific exports
ignoreExportsUsedInFile: {
interface: true, // Ignore interfaces used only in same file
type: true, // Ignore types used only in same file
},
// Ignore workspace packages
ignoreWorkspaces: ['packages/deprecated/**'],
};
// Ignore unused export
// @knip-ignore-export
export const unusedFunction = () => {};
// Ignore unused dependency in package.json
{
"dependencies": {
"some-package": "1.0.0" // @knip-ignore-dependency
}
}
// knip.ts - Whitelist specific exports
const config: KnipConfig = {
entry: ['src/index.ts'],
project: ['src/**/*.ts'],
// Only these exports are allowed to be unused (public API)
exports: {
include: ['src/index.ts'],
},
};
name: Knip
on:
push:
branches: [main]
pull_request:
jobs:
knip:
name: Check for unused code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm ci
- name: Run Knip
run: npx knip --production
- name: Run Knip (strict)
run: npx knip --max-issues 0
knip:
image: node:lts
stage: test
script:
- npm ci
- npx knip --production
only:
- merge_requests
- main
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: knip
name: Knip
entry: npx knip
language: system
pass_filenames: false
# Fastest check - only dependencies
npx knip --dependencies
# Exit with error if any unused dependencies
npx knip --dependencies --max-issues 0
Use in CI to enforce strict dependency hygiene.
# Check for unused exports
npx knip --exports
# Allow exports used in same file
npx knip --exports --exclude-exports-used-in-file
Use for libraries to ensure clean public API.
# Check production code only
npx knip --production
# Check everything (including dev dependencies)
npx knip
// knip.ts
const config: KnipConfig = {
workspaces: {
'.': {
entry: ['scripts/**/*.ts'],
ignoreDependencies: ['@org/internal-package'],
},
'packages/web': {
entry: ['src/index.ts', 'src/App.tsx'],
ignoreDependencies: ['react', 'react-dom'], // Provided by parent
},
'packages/api': {
entry: ['src/server.ts'],
},
},
};
# Check all workspaces
npx knip
# Check specific workspace
npx knip --workspace packages/web
✓ No unused files
✓ No unused dependencies
✗ 2 unused exports
src/utils.ts:
- calculateTax (line 42)
- formatDate (line 58)
src/types.ts:
- UserRole (line 12)
| Type | Description | Action |
|---|---|---|
| Unused file | File not imported anywhere | Delete or add to entry points |
| Unused dependency | Package in package.json not used | Remove from dependencies |
| Unused export | Exported but never imported | Remove export or make private |
| Unused type | Type/interface exported but unused | Remove or make internal |
| Unused enum member | Enum member never referenced | Remove member |
| Duplicate export | Same export from multiple files | Consolidate exports |
// knip.ts
const config: KnipConfig = {
// Ignore exports that are used via side effects
ignoreExportsUsedInFile: true,
// Or add to entry points
entry: ['src/index.ts', 'src/side-effect-file.ts'],
};
# Debug configuration
npx knip --debug
# Manually specify entry points
npx knip --entry src/index.ts --entry src/cli.ts
# Exclude node_modules explicitly (usually automatic)
npx knip --exclude '**/node_modules/**'
# Use .gitignore patterns
npx knip --include-libs false
# Increase memory limit
NODE_OPTIONS=--max-old-space-size=4096 npx knip
// knip.ts - Force enable plugin
const config: KnipConfig = {
vite: {
entry: ['vite.config.ts'],
config: ['vite.config.ts'],
},
};
// package.json - Knip detects binaries in scripts
{
"scripts": {
"lint": "eslint .", // Detects eslint dependency
"test": "vitest" // Detects vitest dependency
}
}
If not detected:
// knip.ts
const config: KnipConfig = {
ignoreDependencies: ['eslint', 'vitest'],
};
# JSON output (for CI)
npx knip --reporter json > knip-report.json
# Compact output
npx knip --reporter compact
# Custom format (coming soon)
npx knip --reporter custom
# Check only changed files (requires git)
npx knip --changed
# Since specific commit
npx knip --changed --base main
// knip.ts
const config: KnipConfig = {
// Include type-only imports as used
includeTypeImports: true,
// Check for unused TypeScript types
types: true,
};
# Easiest wins first
npx knip --dependencies
# Then move to exports
npx knip --exports
# Finally check files
npx knip --files
// knip.ts - Start strict, then relax
const config: KnipConfig = {
// Start with critical paths only
entry: ['src/index.ts'],
project: ['src/core/**/*.ts'],
// Expand coverage over time
// entry: ['src/**/*.ts'],
// project: ['src/**/*.ts'],
};
# Check dependencies in CI (fast, high value)
- name: Check unused dependencies
run: npx knip --dependencies --max-issues 0
# Check exports in PR (prevents API bloat)
- name: Check unused exports
run: npx knip --exports
if: github.event_name == 'pull_request'
--production