Hardens vibe-coded Next.js/React/Node apps by removing proven-dead imports, unused files, and broken refs without rewriting working routes. Use when a rapidly built app works but is messy before launch. Not for greenfield features, broad architecture rewrites, or deleting files still referenced by routes or APIs.
Hardens vibe-coded Next.js/React/Node apps by removing proven-dead imports, unused files, and broken refs without rewriting working routes. Use when a rapidly built app works but is messy before launch. Not for greenfield features, broad architecture rewrites, or deleting files still referenced by routes or APIs.
A safe, incremental cleanup workflow for AI-generated / vibe-coded fullstack apps.
The goal is to make the codebase production-ready without breaking anything that already works.
Surgery, not demolition. Remove only what is provably dead. Preserve everything else.
When to Use
Use when a rapidly built app works but has broken imports, duplicated logic, dead code, unclear environment variables, or fragile release hygiene.
Use before launch or handoff to convert exploratory code into a maintainable production baseline.
Use when cleanup must preserve existing behavior and avoid broad rewrites of routes, APIs, auth, data models, or integrations.
Node.js project with a working package.json and installable dependencies.
TypeScript recommended but not required (type-check commands assume TS; skip if pure JS).
Git repository with a clean working tree so each batch can be reverted independently.
Windows host is primary. Use PowerShell for file-system and grep commands. Bash equivalents are provided where the toolchain expects POSIX shells (e.g., npx tsc).
Consolidation templates and env-var documentation patterns are in Steps 4–5 of this file.
Procedure
Step 1 — Reconnaissance (read before touching)
Before changing anything, map the codebase. Do NOT change anything yet — document findings only.
Broken imports cause build failures and must be fixed before anything else.
# TypeScript: list all errors
npx tsc --noEmit 2>&1
Common patterns to fix:
Missing file (file was deleted or renamed)
Wrong relative path (../lib vs ../../lib)
Named export that doesn't exist
Fix rule: Fix the import reference. Do NOT delete the referenced file unless you've confirmed it's unused everywhere (Step 3).
Step 3 — Identify Dead Code (verify before removing)
A file/export is safe to remove only if all three are true:
No other file imports it (grep-confirmed)
It's not referenced in config, sitemap, or route manifest
It's not a public-facing URL (page.js, route.js)
PowerShell:
# Check if a file is imported anywhere
Select-String -Path *.js,*.jsx,*.ts,*.tsx -Recurse -Pattern 'my-file' | Select-Object Path, LineNumber, Line
# Check if a component is used anywhere
Select-String -Path *.js,*.jsx,*.ts,*.tsx -Recurse -Pattern 'MyComponent' | Select-Object Path, LineNumber, Line
If build or typecheck breaks → revert the last batch before continuing.
Step 7 — Commit Strategy
Each commit should be a single logical unit:
fix: remove broken import in app/blog/page.js
refactor: consolidate social metadata into lib/socialMetadata.js
chore: remove verified-unused utils/oldHelper.js
fix: standardize env var references to NEXT_PUBLIC_BASE_URL
Never bundle UI changes + logic changes + file deletions in one commit. Smaller commits = easier rollback.
Pitfalls
NEVER do these (hard rules)
Never rewrite working systems for cosmetic reasons.
Never rename routes, slugs, or API endpoints that may be indexed or cached.
Never change tool inputs/outputs, API contracts, DB schema, or auth flow.
Never delete files you haven't verified are unused (grep-confirmed + config-checked).
Never make broad sweeping changes in a single commit.
Never add real secrets to version control. Use YOUR_KEY placeholders only.
Never bundle UI changes + logic changes + file deletions in one commit.
Off-limits areas (unless there's a verified bug)
Area
Why
Route slugs / page paths
May be indexed by Google
API route contracts
Callers depend on exact shape
DB schema / Prisma models
Migration required
Auth flow logic
Security-sensitive
Third-party integration configs
Keys/webhooks are environment-specific
Working tool pages
User-facing functionality
Common mistakes
Deleting a file that is dynamically imported (e.g., await import(...) or Next.js dynamic routes) — grep for string-based imports too.
Removing an "unused" export that is actually consumed by a barrel file (index.js re-exports).
Consolidating route handlers that look similar but have different response contracts.
Forgetting that process.env.NEXT_PUBLIC_* vars are inlined at build time — renaming them requires a rebuild and may break cached clients.
Verification
Run the full validation suite after the final batch:
# 1. TypeScript — zero errors expected
npx tsc --noEmit
# Expected: no output, exit code 0# 2. Lint — zero warnings
npx eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 0
# Expected: no output, exit code 0# 3. Build — must succeed
npm run build
# Expected: "✓ Compiled successfully" or equivalent, exit code 0# 4. Tests — pass or no tests
npm test -- --runInBand --passWithNoTests
# Expected: all suites green or "No tests found"
Cleanup checklist — confirm every item:
TypeScript errors fixed
No broken imports
Dead code removed (grep-verified)
Shared helpers created for repeated patterns (3+ uses)
No hardcoded secrets or local-only URLs
All env vars documented in .env.example
Build passes
Tests pass (or no tests exist)
Lint passes
Each commit is scoped and explainable
Limitations
Does not infer product intent from code alone; confirm behavior before deleting routes, components, API contracts, or data models.
Cleanup should be applied in small reviewed batches because broad refactors can hide regressions.
Avoid changing auth, billing, persistence, or third-party integration behavior without explicit requirements and tests.