You open Disk Utility, see a red storage bar, and track the problem down to node_modules — scattered across a dozen project folders, silently consuming tens of gigabytes. If your MacBook is running out of space and node_modules is the culprit, you are not alone, and the fix is methodical rather than mysterious.
Why node_modules Gets So Big
Node's package manager (npm, yarn, or pnpm) installs every dependency — and every dependency's dependency — into a local node_modules folder inside each project. There is no global deduplication by default. A project using Create React App, for instance, pulls in several hundred transitive packages. Multiply that by the number of repositories cloned to your machine and the numbers compound quickly.
- Flat installs: npm v3+ uses a flat
node_modulestree that avoids deep nesting but still stores one copy per project. - No automatic pruning: When you stop working on a project and move on, its
node_modulesstays on disk indefinitely. - Hard links are off by default: Only pnpm uses a global content-addressable store with hard links; npm and yarn write full copies each time.
- Large binary dependencies: Packages like
canvas,sharp, or Electron ship platform-specific native binaries that can each be hundreds of megabytes.
None of this is a bug — it is intentional design that prioritises reproducibility over disk efficiency. The cost is that stale projects leave enormous footprints.
Find Every node_modules Folder on Your Mac
Before deleting anything, map the full picture. Open Terminal and run a find command from your home directory:
find ~ -type d -name "node_modules" -not -path "*/node_modules/*/node_modules" 2>/dev/null
The -not -path clause prevents recursing into nested node_modules (which can take forever). This lists the top-level folder for each project.
To see the size of each one alongside the path, pipe through du:
find ~ -type d -name "node_modules" -not -path "*/node_modules/*/node_modules" -prune 2>/dev/null \
| xargs du -sh 2>/dev/null \
| sort -rh
This sorts results largest-first so you can immediately see which projects account for the most space. On a machine with many cloned repos it is common to find totals of 20–50 GB or more.
Visualise the Bloat With a Disk Map
Terminal output is accurate but hard to scan at a glance. Crumb's built-in treemap lets you navigate your entire disk visually — large rectangles correspond to large directories, so a fat node_modules folder inside ~/Developer/old-startup-idea/ becomes immediately obvious even if you had forgotten the project existed. Select any rectangle and Crumb shows the exact path and size, which makes it easy to cross-reference with your find output before removing anything.
Deciding What Is Safe to Delete
Deleting node_modules is almost always safe, with one important caveat: any project currently running (a dev server, a build process, or a deployed Lambda using a local copy) will break immediately. Follow this checklist before removing a folder:
- Check whether the project is running. In Activity Monitor or with
ps aux | grep node, confirm no Node process is serving from that project directory. - Confirm a
package.jsonorpackage-lock.jsonexists. If it does, you can restore node_modules at any time withnpm install. If those files are missing, the deletion is not truly reversible. - Consider project age. An active project you open daily is a poor candidate. A two-year-old prototype you have not touched since changing jobs is ideal.
- Check for uncommitted build artifacts. Some projects commit compiled output alongside source. If
node_modulescontains a custom build tool output that is not otherwise tracked, document it first.
Important: Deletion is permanent unless you have a Time Machine backup. If in doubt, move the folder to the Trash and leave it there for a week before emptying.
Remove node_modules From Stale Projects
Once you have identified safe targets, remove them individually:
rm -rf ~/Developer/old-project/node_modules
To automate removal across all projects in a directory (use with caution — review the find output first):
# Dry run first — just prints paths, removes nothing
find ~/Developer -type d -name "node_modules" -prune -not -path "*/node_modules/*/node_modules"
# Only run the actual deletion after you have reviewed the list above
find ~/Developer -type d -name "node_modules" -prune -exec rm -rf {} + 2>/dev/null
Running the dry run first is not optional — it takes two seconds and prevents accidentally nuking a folder you needed.
Prevent the Problem From Recurring
Cleaning up once is satisfying; keeping the disk tidy over time is better. A few habits help:
- Switch to pnpm for new projects.
pnpmmaintains a single global store at~/.pnpm-storeand hard-links packages into each project. A dependency shared across ten projects is stored once, not ten times. - Add a Git hook or CI rule. Some teams add a
post-mergehook that runsnpm ciso the local install stays current, but this does not address stale repos. - Archive old repos. When a project is truly finished, zip the source (without node_modules) and remove the live directory. A 200 MB zip replaces what might have been a 2 GB directory.
- Run a quarterly audit. Add a recurring reminder to re-run the
find … ducommand above every few months. Disk creep is gradual enough that it goes unnoticed until the storage bar turns red. - Use
.npmrcto set a global cache location and understand it. npm keeps a separate download cache at~/.npm. This cache is safe to clear withnpm cache clean --force— npm will re-download packages as needed. It does not contain live installs.
Other Developer-Related Disk Hogs to Know About
While you are auditing, other directories commonly surprise developers on macOS:
| Location | What it is | Safe to clear? |
|---|---|---|
~/.npm |
npm download cache | Yes — npm cache clean --force |
~/.gradle/caches |
Gradle build cache (Android/JVM projects) | Yes, with caution on active builds |
~/Library/Developer/Xcode/DerivedData |
Xcode build products | Yes — Xcode rebuilds on next open |
~/Library/Caches/com.apple.dt.Xcode |
Xcode simulator runtimes and caches | Mostly yes; check Xcode → Settings → Platforms first |
~/.docker |
Docker images and volumes | Use docker system prune — not manual deletion |
~/.cargo/registry |
Rust package registry cache | Yes — cargo cache -a |
A Faster Way to See the Full Picture
If you would rather skip the command-line archaeology, download Crumb and use its Visualize tab to get an interactive disk map of your entire Mac in seconds. Click into any folder to see its contents by size, which makes it trivial to spot that 18 GB node_modules buried three levels deep in a subfolder you have not opened in two years. From there you can jump straight to that path in Finder and remove it intentionally.
The Short Version
node_modules taking up too much space is an expected consequence of per-project local installs — not a macOS bug or a bad package. The solution is a one-time audit using find and du, careful review of what is safe to delete, and a handful of long-term habits (pnpm, archiving finished work, quarterly checks) that keep the problem from returning. Disk space you recover today will be consumed again by tomorrow's projects unless you change the underlying workflow.