codebase-health-check
v2.3.2
Published
Analyze your codebase for unused imports, exports, orphan files, dead code, and unused i18n keys.
Maintainers
Readme
Codebase Health Check
A static analysis CLI tool for Next.js, React, and TypeScript projects. Detects unused code, performance bottlenecks, and code quality issues. Provides interactive fixing with review-before-apply workflow.
Quick Start (No Installation Required)
You can run the tool directly using npx. npx will temporarily download and execute the tool on-the-fly without saving it permanently to your computer. Just navigate to your project directory and run:
# Code Cleanup (Unused imports, exports, files, i18n keys)
npx codebase-health-check analyze -d . --fix
# Performance (Unused packages, circular deps, console.logs, assets)
npx codebase-health-check analyze performance -d . --fix
# Code Quality (Large files, duplicate code, TODOs, env vars)
npx codebase-health-check analyze quality -d . --fixGlobal Installation (Optional)
If you plan to use the tool frequently across multiple projects, you can install it globally on your machine. This makes the shorter chc command available everywhere.
npm install -g codebase-health-check
# Now you can use the short command:
chc analyze -d . --fixAnalysis Modes
| Command | Purpose |
| --------------------------- | ---------------------------------------------------------------------------- |
| analyze or analyze code | Unused imports, exports, orphan files, commented-out refs, unused i18n keys |
| analyze performance | Unused npm packages, circular deps, console statements, unused public assets |
| analyze quality | Large files, duplicate code, TODO/FIXME markers, unused env variables |
Each mode generates a markdown report and supports --fix for interactive fixing.
Code Cleanup
🔴 Unused Imports
Import statements that are never referenced in the file body. The tool parses the AST (Abstract Syntax Tree) to accurately distinguish between an identifier declared in an import and the same identifier used in executable code.
Cause: Refactoring that removes usage but leaves the import. Copy-pasting code between files.
// Before
import { ArrowRight, Loader2 } from 'lucide-react';
import { useEffect, useState } from 'react';
export default function MyComponent() {
useEffect(() => {}, []);
return <ArrowRight />;
}
// After fix — Loader2 and useState removed
import { ArrowRight } from 'lucide-react';
import { useEffect } from 'react';
export default function MyComponent() {
useEffect(() => {}, []);
return <ArrowRight />;
}Fix behavior: Removes individual specifiers from the import clause. If all specifiers are unused, removes the entire import statement.
🟠 Unused Exports
Functions, types, variables, or classes marked with export that are never imported by any other file in the project. The tool scans every source file and checks whether each exported name appears in another file's import statements.
Cause: Utility functions written for features that were later removed. Speculative exports created "just in case."
// Before — formatPriceWithTax is exported but never imported anywhere
export function formatPriceWithTax(price: number, tax: number): string {
return `$${(price * (1 + tax)).toFixed(2)}`;
}
// After fix — export keyword removed, function preserved
function formatPriceWithTax(price: number, tax: number): string {
return `$${(price * (1 + tax)).toFixed(2)}`;
}Fix behavior: Strips the export keyword. The declaration itself is preserved because it may be used locally. If it isn't, subsequent runs will flag it.
Risk: Exports consumed by external projects or dynamically loaded modules won't be detected as "used." The tool prompts for confirmation and supports exclusion lists.
🟡 Orphan Files
Source files that exist in the project directory but are never referenced via import or export from in any other file. These are fully disconnected from the module graph.
Cause: Replaced components left behind after refactoring. Files copied from other projects for reference. Experimental code that was never integrated.
src/components/
header.tsx ← imported by layout.tsx
search-box.tsx ← imported by header.tsx
search-box-old.tsx ← not imported anywhere (orphan)Fix behavior: Deletes the file. The tool supports exclusion lists for files you intentionally keep (e.g., work-in-progress).
Automatic exclusions: Next.js entry points (page.tsx, layout.tsx, route.ts, middleware.ts, loading.tsx, error.tsx, not-found.tsx) are never flagged as orphans because the framework consumes them implicitly.
🔵 Commented-out References
A sub-category of orphan files. The file itself is an orphan (not imported anywhere), but its component name still appears inside commented-out JSX or JavaScript in another file. This indicates a component that was intentionally disabled but never cleaned up.
Cause: Temporarily disabling a component with {/*<Component />*/} and removing its import, then forgetting about both.
// layout.tsx — before
<Header />
{/*<CookieConsent />*/} // ← commented-out reference
<Footer />
// layout.tsx — after fix
<Header />
<Footer />The file cookie-consent.tsx is also deleted.
Fix behavior: Two operations: (1) deletes the orphan source file, (2) removes the commented-out lines from referencing files.
🟢 Unused i18n Keys
Translation keys defined in locale JSON files (e.g., messages/fr.json) that are never referenced in any source file. The tool understands next-intl patterns including useTranslations('namespace') and getTranslations('namespace').
Cause: Removed UI sections whose translation keys remain. Keys added speculatively during development.
// Before
{
"cart": {
"title": "Panier",
"empty": "Votre panier est vide",
"summer_sale_2023": "Offre spéciale été 2023!"
}
}
// After fix — summer_sale_2023 removed
{
"cart": {
"title": "Panier",
"empty": "Votre panier est vide"
}
}Fix behavior: Deletes unused keys from all locale files in the messages directory (fr.json, en.json, tr.json, etc.), not just the primary one.
Dynamic key handling: If a key's parent namespace is used with a variable (e.g., t(dynamicKey)), the tool classifies those keys as "potentially dynamic" and does not auto-delete them.
Performance
🔴 Unused npm Dependencies
Packages listed in package.json (dependencies and devDependencies) that are never imported or required in any source file. These inflate node_modules size, slow down installation, and increase the attack surface.
Cause: Trying a package and deciding not to use it. Migrating from one library to another without removing the old one.
Fix behavior: Prints exact npm uninstall commands. Auto-removal is intentionally avoided because some packages are consumed implicitly (PostCSS plugins, ESLint configs, TypeScript type definitions). Common implicit packages are pre-excluded.
🟠 Circular Dependencies
Import cycles where File A imports File B, which imports File C, which imports File A. These cause unpredictable module initialization order, undefined values at runtime, and slower bundling.
Cause: Utility modules that gradually start depending on each other. Shared type files importing from files that import them back.
auth.ts → user.ts → permissions.ts → auth.tsFix behavior: Informational only. The report shows exact cycle paths. Common resolution strategies: extract shared types into a dedicated file, use dependency injection, or restructure module boundaries.
🟡 Console Statements
console.log, console.warn, console.error, console.debug, and console.info calls left in source code. These are almost always debugging leftovers that should not reach production.
Cause: Debugging during development. Copy-pasted code from documentation or Stack Overflow.
// Before
export function addToCart(item: CartItem) {
console.log('addToCart called', item);
return dispatch({ type: 'ADD', payload: item });
}
// After fix
export function addToCart(item: CartItem) {
return dispatch({ type: 'ADD', payload: item });
}Fix behavior: Removes the entire statement line, including multi-line console calls. Lines inside comments are ignored.
🔵 Unused Public Assets
Files in the public/ directory (images, fonts, PDFs, videos) that are never referenced by filename in any source file, CSS file, or configuration file. These inflate the deployment bundle.
Cause: Replacing images without deleting the old versions. Assets downloaded for designs that were never implemented.
Fix behavior: Deletes unreferenced files. favicon.ico, robots.txt, sitemap.xml, and manifest.json are automatically excluded.
Code Quality
🔴 Large Files
Source files exceeding 300 lines. Large files typically contain multiple concerns and benefit from being split into focused modules.
Fix behavior: Informational. The report lists files sorted by line count to help prioritize refactoring.
🟠 Duplicate Code Blocks
Blocks of 6+ consecutive lines that are identical across two or more files. These indicate copy-paste patterns that should be extracted into shared utilities.
Fix behavior: Informational. The report shows the duplicated code and all locations where it appears.
🟡 TODO/FIXME/HACK Comments
Comments containing TODO, FIXME, HACK, XXX, or BUG markers. These represent acknowledged technical debt.
Fix behavior: Informational. The report groups findings by marker type with file locations and content.
🟢 Unused Environment Variables
Variables defined in .env, .env.local, or .env.production that are never referenced via process.env.VARIABLE_NAME in source or config files.
Cause: Removed features whose env variables remain. Renaming variables in code without updating .env.
Fix behavior: Informational. Variables like NODE_ENV, PORT, and HOSTNAME are automatically excluded.
Interactive Fix Workflow
Adding --fix to any analysis command enters interactive mode:
npx codebase-health-check analyze -d . --fix
npx codebase-health-check analyze performance -d . --fixStep 1 — Select issues:
# Issue Count
─── ──────────────────────────── ────────────────────
1 🔴 Unused Imports 8 in 4 files
2 🟠 Unused Exports 192 in 92 files
3 🟡 Orphan Files 74 files
4 🔵 Commented-out Refs 16 files
5 🟢 Unused i18n Keys 3 keys
Select issues to fix (numbers or "all"): 1,3,4Step 2 — Review destructive operations:
Orphan Files — this is a destructive operation.
review and exclude some? (y/n): y
fix plan saved: /project/chc-fix-plan.json
edit the "exclude" arrays, then run:
npx codebase-health-check fixStep 3 — Edit and apply:
Add paths to the "exclude" array in the generated JSON file, then:
npx codebase-health-check fix -d .If no exclusions are needed, answer n to the review prompt and fixes are applied immediately.
Options
| Option | Default | Description |
| -------------------------- | ---------- | -------------------------------- |
| -d, --dir <path> | . | Root directory to analyze |
| -l, --locales-dir <path> | messages | Locale JSON directory |
| --default-locale <file> | fr.json | Primary locale file for analysis |
| --fix | false | Enable interactive fix mode |
Generated Reports
| Command | Output file |
| -------------------------- | ----------------------------- |
| analyze / analyze code | health-check-report.md |
| analyze performance | health-check-performance.md |
| analyze quality | health-check-quality.md |
Framework Support
- Next.js (App Router and Pages Router)
- React (TypeScript and JavaScript)
- next-intl (namespace-aware i18n analysis)
- Path aliases (
@/resolves tosrc/)
Ignoring Files
Create .chcignore in the project root (.gitignore syntax):
**/*.test.ts
**/*.spec.ts
src/legacy/**Existing .gitignore rules are also respected.
License
MIT
