From codebase-analysis
Find unused files, exports, types, and package dependencies using knip. Use when asked to find dead code, unused exports, or files that can be deleted.
How this skill is triggered — by the user, by Claude, or both
Slash command
/codebase-analysis:dead-code-analysisThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use knip to find unused files, exports, types, and package.json dependencies.
Use knip to find unused files, exports, types, and package.json dependencies.
This skill works with any TypeScript/JavaScript project:
# Dead code analysis
pnpm analyze:dead
# Exports and types only (less noise)
pnpm analyze:dead:exports
# Dependencies only
pnpm analyze:dead:dependencies
knip exits code 1 when issues are found — this is expected, not a tool error.
Unused files (1)
src/config.ts
Unused dependencies (2)
some-package package.json:12
another-package package.json:18
Unused exports (3)
processItem function src/services/processor.ts:42:23
CONFIG const src/config/settings.ts:5:14
helperFn function src/utils/helpers.ts:18:17
Unused exported types (2)
ProcessOptions interface src/services/processor.ts:10:18
ResultShape interface src/utils/helpers.ts:4:18
| Output section | What it means |
|---|---|
| Unused files | Entire file has no importer anywhere in the project |
| Unused exports | Symbol is exported but not imported by any other module |
| Unused types | Type/interface exported but never imported externally |
| Unused dependencies | package.json dependency with no import in src/ |
Do not default to removing unused exports. An unused export is a question that needs investigation before any action.
Step 1 — Is it called within its own file?
grep -n "symbolName" src/path/to/file.ts
If yes: the export is preemptive. The function is used — just not externally.
Step 2 — Is there another piece of code doing the same job?
grep -rn "similarFunctionName\|keywordFromImplementation" src/ --include="*.ts"
If you find code elsewhere doing the same thing without calling this function: a parallel implementation exists.
Step 3 — Is there a consumer that SHOULD exist but doesn't?
Check whether there is a route, handler, or caller that logically belongs to this function.
Step 4 — Does the surrounding code suggest a changed direction?
Read the function and its neighbors. If the type signatures suggest a workflow that was replaced by a different approach, the function is orphaned.
| Category | Description | Action |
|---|---|---|
| A — Preemptive export | Called within its own file; export added for a future caller | Safe to remove export keyword when ready |
| B — Wiring gap | Complete, correct, but no external caller exists yet | Identify what should be calling it and wire it up |
| B (bypassed) | Another piece of code does the same job without calling this | Consolidate — replace inline code with a call to this function |
| C — Changed direction | Built for a feature that moved differently; genuinely orphaned | Document and either delete or preserve |
// utils/validation.ts — exported but knip says unused
export function validateRequiredFields(data: Record<string, unknown>, required: string[]): string | null {
for (const field of required) {
if (!data[field]) return `Missing required field: ${field}`;
}
return null;
}
// handlers/items.ts — does NOT import validateRequiredFields
if (!req.body.name || !req.body.type) {
return res.status(400).json({ error: "Missing required fields" });
}
This is a bypassed utility — the handler reimplements inline what the utility was built to do.
eslint.config.js outside src/clsx, tailwind-merge, cn() utilities) — used via config or theme files that knip doesn't traceapp/ or pages/ may be used via file-system routing, not importsIn Next.js with App Router, knip may flag files as unused that are actually entry points via routing:
| File | Why it may be flagged | Is it safe to delete? |
|---|---|---|
app/page.tsx | No explicit import | No - used by Next.js router |
app/layout.tsx | No explicit import | No - used by Next.js router |
app/error.tsx | No explicit import | No - used by Next.js router |
app/not-found.tsx | No explicit import | No - used by Next.js router |
app/route.ts | No explicit import | No - used by Next.js router |
Configuration:
{
"entry": ["app/page.tsx", "app/layout.tsx", "app/router.ts", "app/route.ts"]
}
For older projects using pages/:
| File | Why it may be flagged | Is it safe to delete? |
|---|---|---|
pages/_app.tsx | No explicit import | No - Next.js entry |
pages/_document.tsx | No explicit import | No - Next.js entry |
pages/api/*.ts | No explicit import | No - API routes |
When building a design system with shadcn/ui:
components/ui/ - All files are intentionally similar (boilerplate). knip won't flag these as duplicates, but jscpd will. Add to jscpd ignore list.lib/utils.ts (cn utility) - Used via string concatenation. Add to knip ignoreDependencies.components.json - No imports but defines component configuration.For libraries without Next.js routing:
index.ts exports all components - this is the entry pointstories/*.tsx files may be unused but are for Storybook developmentIf using Tailwind without PostCSS processing in knip:
{
"ignoreDependencies": ["tailwindcss", "clsx", "tailwind-merge"]
}
The cn() function in lib/utils.ts is used via template strings which knip cannot trace.
{
"entry": ["app/page.tsx", "app/layout.tsx", "app/router.ts"],
"project": ["app/**/*.ts", "app/**/*.tsx", "components/**/*.ts", "components/**/*.tsx", "lib/**/*.ts"],
"ignore": [
"app/**/page.tsx",
"app/**/layout.tsx",
"app/**/not-found.tsx",
"app/**/error.tsx",
"components/ui/**",
"**/__tests__/**",
"**/*.test.ts",
"**/*.test.js"
],
"ignoreDependencies": ["clsx", "tailwind-merge", "class-variance-authority"],
"ignoreExportsUsedInFile": true
}
{
"entry": ["pages/_app.tsx", "pages/_document.tsx"],
"project": ["pages/**/*.ts", "pages/**/*.tsx", "components/**/*.ts", "lib/**/*.ts"],
"ignore": ["components/ui/**", "**/__tests__/**"],
"ignoreDependencies": ["clsx", "tailwind-merge"],
"ignoreExportsUsedInFile": true
}
{
"entry": ["src/index.ts"],
"project": ["src/**/*.ts", "src/**/*.tsx"],
"ignore": ["src/components/ui/**", "src/stories/**", "**/*.test.ts"],
"ignoreDependencies": ["clsx", "tailwind-merge"],
"ignoreExportsUsedInFile": true
}
{
"entry": ["src/index.ts"],
"project": ["src/**/*.ts"],
"ignore": ["src/**/__tests__/**", "src/**/*.test.ts"],
"ignoreExportsUsedInFile": false,
"rules": {
"files": "error",
"exports": "error",
"dependencies": "warn"
}
}
Dead code findings gain more meaning when combined with jscpd results.
Knip reports an unused export + jscpd reports that same code is duplicated elsewhere = bypassed utility
This combination means: the utility exists, nobody imports it, AND the logic was written again inline somewhere.
npx claudepluginhub kylebrodeur/codebase-analysis --plugin codebase-analysisDetects unused files, dependencies, exports, and types in JavaScript/TypeScript projects using Knip. Plugins support React, Next.js, Vite, Vitest, Jest for codebase cleanup, bundle optimization, CI hygiene.
Detects dead code, unused exports, orphaned files, circular dependencies, unused packages, stale TODOs, and hygiene issues across 11 categories. Use scan, safe, aggressive modes on full codebase or paths.
Identifies unused imports, variables, functions, unreachable code, dependencies, and CSS for safe removal. Generates reports categorizing safe-to-remove, potentially unused, and review-required items.