Deleting node_modules is safe: npm install (or pnpm install, yarn, bun install) rebuilds it from package.json and the lockfile. Find every copy with find and du, or run npx npkill for an interactive list, and remove the ones in projects you aren't working on. In pnpm projects, deleting node_modules alone frees little, because the files are hard links into pnpm's shared store; run pnpm store prune afterwards to actually get the space back.
Is it safe to delete node_modules?
Yes. node_modules contains nothing you wrote: it's the installed copy of the dependencies listed in package.json, pinned by your lockfile (package-lock.json, pnpm-lock.yaml, yarn.lock or bun.lock). Deleting it and reinstalling gives you the same tree back.
A few things to know before you start:
- Check the lockfile is there. Without one, reinstalling resolves the newest versions allowed by
package.json, which may not be what you had. - Stop dev servers and watchers running from that project first.
- Some packages download extra files on install. Playwright, Puppeteer, Electron and native modules fetch browsers or binaries in a postinstall step. Many of those land in shared caches outside
node_modules, so reinstalling is usually quick, but expect a download the first time. - You need the network to reinstall, unless your package manager's cache already has everything.
- Global packages aren't affected. Tools installed with
npm install -glive elsewhere.
A single project's node_modules is often 100 MB to 1 GB. The problem is that every project, every clone and every old experiment has its own.
How do I find every node_modules folder?
Point find at the folder where you keep code. -prune stops it from descending into each node_modules, so nested ones aren't counted twice and it stays fast:
# every node_modules under ~/Projects, largest first $ find ~/Projects -type d -name node_modules -prune -exec du -sh {} + 2>/dev/null | sort -hr # only ones not modified in the last 90 days $ find ~/Projects -type d -name node_modules -prune -mtime +90 -exec du -sh {} + 2>/dev/null | sort -hr
The modification date is that of the node_modules folder itself, which changes when packages are added or removed. It's a good hint for "I haven't installed anything here in months", not proof that the project is dead.
To search your whole home folder instead, replace ~/Projects with ~. It's slower, and it will also find node_modules inside apps and tools you've installed, which you should leave alone (see below).
npkill
npkill is a free, open-source command-line tool that lists every node_modules folder under the current directory with its size, and lets you delete them one by one with the space bar:
$ cd ~/Projects $ npx npkill
It's quick and pleasant to use. Two things to know: its deletion is immediate (it erases the folder rather than moving it to the Trash), and its README warns that some applications need their node_modules to work, marking those with a warning sign.

How do I delete node_modules but keep a way back?
For one folder, move it to the Trash:
$ mv ~/Projects/old-app/node_modules ~/.Trash/For many at once, the Trash has a catch: every folder has the same name, and mv refuses to overwrite one already in the Trash. On macOS 15 and later the built-in trash command handles that by renaming duplicates for you:
# macOS 15+: move every node_modules untouched for 90+ days to the Trash $ find ~/Projects -type d -name node_modules -prune -mtime +90 -exec trash -v {} +
On older macOS, give each one a unique name:
$ find ~/Projects -type d -name node_modules -prune -mtime +90 -print | $ while IFS= read -r d; do $ mv "$d" ~/.Trash/"node_modules-$(basename "$(dirname "$d")")-$RANDOM" $ done
Everything above stays in the Trash until you empty it. When you return to a project, run its install command and carry on.
Why does deleting node_modules in pnpm projects free so little?
pnpm keeps one copy of each package file in a content-addressable store and hard-links those files into each project's node_modules. On macOS, the default store is ~/Library/pnpm/store, and pnpm store path shows yours.
pnpm's FAQ explains the effect: a dependency that "occupies 1MB of space" looks like it uses 1 MB in the project's node_modules and the same amount in the store, but "that 1MB is the same space on the disk addressed from two different locations." So:
duoverstates what deleting a pnpmnode_moduleswill free.- Deleting it removes one of two names for the same bytes; the store still holds them.
- The space comes back when you run
pnpm store prune, which removes packages that no project references any more.
$ pnpm store path $ pnpm store prune
pnpm's docs say pruning "is not harmful and has no side effects on your projects", but recommend running it occasionally rather than constantly, since a package you prune may be needed again when you switch branches, and then it's downloaded again. pnpm can't tell you in advance how much a prune will free.
Hard links only work on the same disk, so if your projects are on an external drive and the store isn't, pnpm copies instead of linking, and both copies take space.
Bun is similar on macOS. Its docs say it installs packages from its global cache (~/.bun/install/cache) using clonefile, which is copy-on-write: the clone shares disk blocks with the cache until one of them changes. Deleting a Bun project's node_modules therefore frees less than du reports.
How do I clear npm, pnpm, Yarn and Bun caches?
Package managers keep a download cache so installs don't hit the network every time. These are safe to clear; the only cost is slower installs until they refill.
| Tool | Default location on macOS | Check | Clear |
|---|---|---|---|
| npm | ~/.npm/_cacache | npm cache verify | npm cache clean --force |
| npx | ~/.npm/_npx | npm cache npx ls | npm cache npx rm (npm 11) |
| pnpm | ~/Library/pnpm/store | pnpm store path | pnpm store prune |
| Yarn 1 (classic) | shown by yarn cache dir | yarn cache dir | yarn cache clean |
| Yarn 2+ (Berry) | ~/.yarn/berry/cache | du -sh ~/.yarn/berry/cache | yarn cache clean --mirror |
| Bun | ~/.bun/install/cache | bun pm cache (inside a project) | bun pm cache rm (inside a project) |
A few notes:
- npm requires
--forcefornpm cache clean. Its docs say the cache is self-healing and clearing it is "never necessary" except to reclaim disk space. Start withnpm cache verify, which garbage-collects unneeded data. - npx keeps every package you've run with
npxin its own folder. On my Mac it was 2.3 GB, seven times the npm cache itself, so it's worth checking withdu -sh ~/.npm/_npx. - Yarn 2+ projects using Plug'n'Play may have no
node_modulesat all; their packages sit in the project's.yarn/cache, which some teams commit to git on purpose. Don't delete that without checking.
# how big are they? $ du -sh ~/.npm/_cacache ~/.npm/_npx ~/Library/pnpm/store ~/.bun/install/cache 2>/dev/null
Which node_modules should I not delete?
- Inside apps and tools. Some apps and globally installed CLIs ship with their own
node_modules(inside.appbundles,/usr/local/lib/node_modules,/opt/homebrew/lib/node_modules, or a version manager's folder such as~/.nvm). Deleting those breaks the tool. - Projects you're actively running, until you've stopped the dev server.
- Projects without a lockfile, unless you're happy to get newer versions.
Searching only your code folders, as in the commands above, avoids all of these.
A quick routine
# 1. what's big $ find ~/Projects -type d -name node_modules -prune -exec du -sh {} + 2>/dev/null | sort -hr | head -20 # 2. trash the old ones (macOS 15+) $ find ~/Projects -type d -name node_modules -prune -mtime +90 -exec trash -v {} + # 3. tidy caches $ npm cache verify $ pnpm store prune
Then empty the Trash once you're sure. For the other usual suspects, see Xcode DerivedData, Docker and the full developer cache reference. For everything else on a full Mac, start with how to free up space on a Mac. Shedi does all of this in one list, with each project's last-modified date shown before anything moves.
