← All articles

You Have 40 GB of node_modules You Forgot About

node_modules taking up space is rarely the project you are on, it is the sixty old ones. How to find every folder, rank by age, and delete the dead ones.

· Updated September 14, 2026
node_modulesnpmJavaScriptStorageDeveloper

The node_modules in the project you have open right now is fine. Leave it alone.

The problem is the other sixty. The tutorial you followed in 2024. The take-home assignment. The three abandoned side projects. The repo you cloned to read one file. Each one carries 200 MB to 1.5 GB of dependencies, and every one of them is perfectly reproducible from a lockfile.

Find every one of them

find ~ -type d -name node_modules -prune -print0 2>/dev/null \
  | xargs -0 -n1 du -sh 2>/dev/null | sort -hr | head -40

Two details in there matter:

  • -prune stops find descending into a node_modules once it has matched it. Without it you get every nested one too, sizes double-count, and the totals are meaningless.
  • -print0 / -xargs -0 survives paths with spaces, which you will have.

Give it a minute on a large home directory. The output is one line per project, biggest first, and it is usually a longer list than people expect.

Rank by last touched, not by size

Size tells you what is expensive. Age tells you what is dead. The second question is the one you actually want answered:

find ~ -type d -name node_modules -prune 2>/dev/null \
  | while read -r d; do
      printf '%s\t%s\n' "$(stat -f '%Sm' -t '%Y-%m-%d' "$d")" "$d"
    done | sort | head -40

That prints oldest first, YYYY-MM-DD then path. Anything last modified more than a year ago is a free deletion — you are not going back to that project this week, and if you do, npm install restores it exactly.

Delete them

Once you have read the list and recognised the projects:

rm -rf ~/projects/old-thing/node_modules

To clear everything untouched in the last year in one pass, look first:

find ~ -type d -name node_modules -prune -mtime +365 -print 2>/dev/null

Read that output. Actually read it. Then, and only then:

find ~ -type d -name node_modules -prune -mtime +365 -print0 2>/dev/null \
  | xargs -0 rm -rf

If you would rather do it interactively, npkill is a well-known npx tool that lists every node_modules in a terminal UI and deletes on keypress:

npx npkill

What you can and cannot restore

You can always restore node_modules as long as the project has a lockfile — package-lock.json, pnpm-lock.yaml or yarn.lock — and the packages are still published. npm ci reproduces the exact tree in seconds.

The three cases where you should stop and think:

  1. No lockfile committed. Restoring gives you today’s versions matching your semver ranges, not the versions that were there. For a project that still needs to build reproducibly, commit the lockfile before you delete.
  2. You patched something inside node_modules by hand. It is gone. If you use patch-package the patches live in patches/ and survive; ad-hoc edits do not.
  3. A dependency has been unpublished or the registry is private and now unreachable. Rare, but npm ci will simply fail. If the project matters and it depends on something fragile, keep it.

The global caches are a separate 5–15 GB

Deleting node_modules folders does not touch your package manager’s global store, which is its own pile:

# npm
du -sh ~/.npm/_cacache
npm cache clean --force

# pnpm — ask it where the store is, the default moves
du -sh "$(pnpm store path)"
pnpm store prune

# Yarn
yarn cache clean

pnpm store prune is the polite one: it removes only packages no longer referenced by any project on your machine. npm cache clean --force empties everything; npm re-downloads on demand, so the only cost is bandwidth.

Why pnpm makes this problem much smaller

If you routinely have a dozen active JavaScript projects, this is the structural fix. pnpm keeps one content-addressed store and hard-links into each project instead of copying. Ten projects sharing React store one copy of React, not ten. Real-world disk use for node_modules typically drops by well over half, and installs get faster as a side effect.

It will not retroactively clean up the npm-installed folders you already have — delete those with the commands above first, then reinstall with pnpm.

This is a recurring tax, not a one-off

You will clone something next week. It will pull 400 MB. In six months you will have forgotten it exists, and the only trace will be a disk-full warning with no explanation attached.

The commands above do this job for free — this is a real problem either way, and it is worth twenty minutes of your attention today. DevCruft, a free Mac app for developers we’re building, is being designed to find every node_modules on every volume, size each one against the rest of your disk with the date you last opened the project, and let you clear the dead ones together. Join the waitlist to hear when it launches.

Next: the full developer storage guide, or what Docker is hiding from you.

A free app for this is on the way.

We’re building DevCruft to find every cache in guides like this one and show what each costs you. Join the waitlist to hear when it launches.

One email at launch, nothing else. Ask us any time to remove you. Privacy policy