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.

Updated 2026-09-20

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 .git boundary. 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.