How to delete node_modules from every project at once
find, npkill, and a lockfile-verified alternative — the three ways to clear node_modules across a whole machine, and what each one risks.
If you have thirty repositories on a laptop, you have thirty node_modules
directories, and most of them belong to projects you have not opened in months. Here are
the three ways people clear them, in increasing order of how much they check first.
1. find, or the PowerShell equivalent
find ~/Code -name node_modules -type d -prune -exec rm -rf {} +
On Windows PowerShell:
Get-ChildItem ~/Code -Recurse -Directory -Filter node_modules |
ForEach-Object { Remove-Item $_.FullName -Recurse -Force }
It works, it takes one line, and it verifies nothing. It will happily delete the
node_modules of the project you are debugging right now, and the one whose
lockfile is out of sync and will not reinstall. -prune in the
find version matters: without it, find descends into directories
it is about to delete and wastes minutes walking a tree it will discard.
2. npkill
npx npkill
npkill is the well-known one, and it is good at what it does: it scans, sorts by size, shows you the last-modified date, and lets you delete interactively with the arrow keys. If you want to look at a list and make thirty individual decisions, this is the tool.
What it does not do is check whether any given directory can be rebuilt. The last-modified date is a proxy for "probably safe" and it is a decent one, but it is a guess, and it is your guess to make on each row.
3. Verify, then delete
The third option is to make the check the tool's job rather than yours. That is what
dev-prune is: it walks the Git repositories you have registered, and for each
one it runs the dry-run that matches the lockfile it found —
npm ci --dry-run --ignore-scripts, pnpm install --lockfile-only,
yarn install --immutable, bun install --frozen-lockfile --dry-run —
before deleting anything. If that command exits non-zero, the directory stays, and
you are told which package was missing from the lockfile.
curl -fsSL https://devprune.vkrishna04.me/install.sh | sh
devp init --auto --dry-run
devp init --auto
devp run --dry-run
devp init --auto works out where your repositories are rather than making
you list them — it looks at the workspace you are in and the conventional code folders
under your home directory — and --dry-run prints what it found without
registering any of it. Name the directory yourself with devp init ~/Code if
you would rather. A repository holding an ignore.devprune.json file is left
out of the scan entirely.
The other three checks it makes are worth knowing, because they are the ones a hand-rolled script never has:
- It will not cross a
.gitboundary. A nested repository inside a repository is a separate decision, not part of the outer one. - It refuses symlinks outright. It never follows one and never deletes through one, which is the failure mode that costs people a pnpm store.
- It only touches repositories that have been idle. Idle means no commit and no working-tree change for a configurable number of days. The project you are working in today is not a candidate, whatever its size.
And it is not only Node: the same pass handles .venv for uv, Poetry, PDM,
Pipenv and plain venv, vendor/ for Go, Composer and Bundler,
deps/ for Mix, Pods/ for CocoaPods: thirty-five package
managers in total, seventeen of them on by default.
Which to use
Clearing one project you are looking at: rm -rf node_modules. Nothing beats
it. Going through a machine by hand once, deciding case by case: npkill. Wanting the machine
to stay clean without you thinking about it, and wanting a refusal rather than a deletion
when something is off: that is the case dev-prune was written for. There is a fuller
comparison, including cargo-sweep, rimraf and the rest, on
dev-prune vs the alternatives.
Common questions
How do I delete all node_modules folders recursively?
On macOS or Linux: find ~/Code -name node_modules -type d -prune -exec rm -rf {} + — the -prune is what stops find from descending into directories it is about to delete. On Windows: Get-ChildItem ~/Code -Recurse -Directory -Filter node_modules | ForEach-Object { Remove-Item $_.FullName -Recurse -Force }. Neither checks whether the directories can be reinstalled.
What is the difference between npkill and dev-prune?
npkill scans for node_modules directories and lets you delete them interactively, sorted by size and last-modified date. dev-prune runs the package manager dry-run that matches each lockfile and deletes only when it exits zero, across twenty-five package managers rather than Node alone, and skips repositories that are not idle.
Is there a way to delete node_modules automatically?
dev-prune registers a background pass with the OS scheduler — Task Scheduler on Windows, launchd on macOS, systemd or cron on Linux — that runs every two days and prunes only repositories that have been idle past your threshold and whose lockfiles verify.