Skip to main content

Pruning RoleReady with Knip

tooling javascript maintenance

WIP — This article is a work in progress.

I ran npx knip on RoleReady. It found 109 files that nothing imported. I deleted them all—15,790 lines gone in one commit.

What Knip Does

Knip traces imports from your entry points (app/layout.tsx, next.config.js, test files) and flags anything unreachable. For Next.js projects it works out of the box:

npx knip

The output lists unused files, unused exports, and unused dependencies. Mine scrolled for pages.

What I Found

Most of the dead code came from features I’d abandoned:

Chrome extension (908 lines). I built a browser extension to scrape job postings from LinkedIn. Switched to a paste-based flow instead. The extension stayed in the repo—background scripts, content scripts, popup UI—for months.

Document management (1,477 lines). Let users attach resumes to applications. Built it, shipped it, nobody used it. Removed the UI but left the components.

20 shadcn/ui components (~2,400 lines). Carousel, chart, command palette, table, pagination. Installed them thinking I’d need them. Never did.

The rest was scattered across hooks, utilities, type definitions, and one-off scripts I wrote to fix database issues and forgot about.

Here’s where it all lived:

components/ui/     38 files changed
components/        23 files changed
lib/               17 files changed
scripts/           12 files changed
hooks/              9 files changed
lib/types/         10 files changed
lib/validation/     7 files changed
chrome-extension/   6 files changed

The Cleanup

I did three passes:

First pass: delete anything obviously dead. Files named interview-management-panel.tsx for a feature that doesn’t exist. Scripts named fix-orphaned-jobs.ts from debugging sessions.

Second pass: verify the rest. Some components might be dynamically imported. Search for the filename, search for the export name, confirm it’s actually unused.

Third pass: run Knip again. Deleting files orphans their dependencies. Repeat until stable.

The final commit touched 194 files. 109 deletions, 85 edits to clean up imports and barrel files.

Why It Matters

The problem isn’t disk space. It’s that I was maintaining this code.

When I upgraded React, I fixed type errors in files nothing imported. When I refactored validation, I updated schemas no route used. TypeScript errors in dead code still block builds.

Search results included components that didn’t run. Grepping for patterns returned files from abandoned features. Every cleanup felt risky because I couldn’t tell what was load-bearing.

Now the codebase matches what actually ships.

Going Forward

{
  "scripts": {
    "lint:unused": "knip"
  }
}

I run it after removing features and before big refactors. Not aiming for zero warnings—some unused exports are intentional—but I want to know what’s dead before I waste time on it.