node_modules is Why Your Mac is Full: Find and Delete All of Them

node_modules folders silently consume tens of gigabytes on your Mac. Find every one, delete them safely, and clean package caches.

I had 47 node_modules folders totaling 38GB on my Mac. Most of them were for projects I hadn’t touched in months. A weekend tutorial from last year? Still has its node_modules. That side project I abandoned after two commits? node_modules. A cloned repo I opened once to read the source? You guessed it — node_modules.

If your Mac keeps telling you the disk is full and you’re a JavaScript developer, there is a very good chance that node_modules is the single biggest reason why. It’s not your photos. It’s not your music. It’s 200,000 tiny files spread across dozens of forgotten project directories.

Let’s fix that.

Why node_modules Gets So Absurdly Big

If you’ve ever looked at a fresh node_modules folder and wondered how a project with three dependencies ended up with 900MB of installed packages, you’re not imagining things. There are real structural reasons why this happens.

Flat Dependency Trees

npm v3 introduced flat dependency trees to solve the deeply nested paths problem on Windows. The trade-off? Every transitive dependency gets hoisted to the top level of node_modules. Install create-react-app and you’ll find yourself with 1,400+ packages in a flat directory. Your project depends on 5 things. Those 5 things depend on 1,395 other things. All of them live in your project folder.

Duplicate Packages Across Projects

Here’s where the math gets painful. If you have 10 React projects on your machine, you likely have 10 complete copies of React, 10 copies of webpack, 10 copies of TypeScript, and 10 copies of every shared dependency between them. There’s no deduplication across projects. Each node_modules is an island.

A typical React project’s node_modules weighs 300-500MB. A Next.js project can hit 600MB-1GB. Multiply that by every project on your machine and you start to see how 20-50GB disappears silently.

Native Binaries and Platform-Specific Code

Some packages include prebuilt native binaries — esbuild, swc, sharp, better-sqlite3, Playwright’s browser binaries. These are often 50-200MB each. They compile or download platform-specific builds during npm install, and they’re not small.

Build Output Hiding in Plain Sight

On top of node_modules itself, most JavaScript projects also generate build output directories: dist, build, .next, .nuxt, out. A Next.js build cache (.next) alone can be 200-500MB. These add up across projects too, and they’re just as safe to delete as node_modules — they regenerate on the next build.

Finding All node_modules on Your Mac

Before you delete anything, let’s see the damage. This command finds every node_modules directory under your home folder and shows its size:

find ~ -name "node_modules" -type d -maxdepth 5 -exec du -sh {} \; 2>/dev/null

You’ll see output like this:

1.2G    /Users/you/projects/webapp/node_modules
487M    /Users/you/projects/api-server/node_modules
923M    /Users/you/code/nextjs-blog/node_modules
341M    /Users/you/tutorials/react-course/node_modules
756M    /Users/you/clients/dashboard/node_modules
...

Want just the total? Pipe it through awk:

find ~ -name "node_modules" -type d -maxdepth 5 -exec du -sm {} \; 2>/dev/null | awk '{total += $1} END {printf "Total: %.1f GB\n", total/1024}'

Fair warning: this command can take a minute or two to run. du has to stat every file inside every node_modules, and there are a lot of files.

If you want a quick count of how many node_modules folders you have without waiting for sizes:

find ~ -name "node_modules" -type d -maxdepth 5 2>/dev/null | wc -l

Don’t be surprised if it’s more than you expected. I never would have guessed 47.

The Nuclear Option: Delete Them All

Once you’ve seen the list, you’ll probably realize that most of these projects don’t need their dependencies installed right now. You can always run npm install (or yarn, or pnpm install) again later when you actually work on a project. The package.json and lockfile are what matter — node_modules is just a cache.

To delete every node_modules folder under your home directory:

find ~ -name "node_modules" -type d -maxdepth 5 -exec rm -rf {} + 2>/dev/null

A few things to know before you run this:

  • It’s safe. node_modules is fully regenerable from your lockfile. Nothing unique lives in there.
  • Running projects will break. If you have a dev server running, it will crash. Stop your dev servers first.
  • You’ll need to reinstall. The next time you cd into a project and run it, you’ll need to npm install first. This is normal.
  • It won’t touch your source code. Only the node_modules directories are deleted. Your package.json, lockfiles, and source files are untouched.

If you want to be more selective — say, only delete node_modules for projects you haven’t modified in over 30 days — that’s harder to do from the command line. You’d need to cross-reference each node_modules with the modification dates of the source files in the parent project directory. (This is actually something MegaCleaner does automatically — more on that below.)

Package Manager Caches: The Other Storage Hog

Deleting node_modules folders is only half the story. Your package manager also keeps a global cache of downloaded packages. This cache speeds up future installs so npm doesn’t have to re-download packages from the registry, but it grows over time and can get large — especially if you work across many projects with different dependency versions.

Here’s where each package manager stores its cache on macOS and how to clean it.

npm

Cache location: ~/.npm

npm’s cache stores tarballs and metadata for every package you’ve ever installed. It grows indefinitely.

# Check size
du -sh ~/.npm

# Clean it
npm cache clean --force

The --force flag is required because npm wants you to really mean it. After cleaning, future installs will be slightly slower for the first run as packages are re-downloaded.

Yarn (v1/Classic)

Cache location: ~/Library/Caches/Yarn

You can verify the exact path on your system:

yarn cache dir

To clean it:

# Check size
du -sh ~/Library/Caches/Yarn

# Clean it
yarn cache clean

pnpm

Cache location: ~/Library/pnpm

pnpm uses a content-addressable store, which is actually more efficient than npm or yarn — it deduplicates packages across projects using hard links. That said, the store still grows over time as you install different package versions.

# Check size
du -sh ~/Library/pnpm

# Remove unreferenced packages
pnpm store prune

pnpm store prune is gentler than a full delete — it removes packages that aren’t referenced by any project on your machine, but keeps the ones that are still in use.

Bun

Cache location: ~/.bun/install/cache

Bun’s cache stores downloaded packages in its own format:

# Check size
du -sh ~/.bun/install/cache

There’s no built-in bun cache clean command as of this writing. To clear it, you can delete the directory manually:

rm -rf ~/.bun/install/cache

Deno

Cache location: ~/.deno

Deno stores downloaded dependencies and compilation caches here:

# Check size
du -sh ~/.deno

Turborepo

Cache location: ~/.turbo

If you use Turborepo for monorepo build orchestration, it maintains a global build cache:

# Check size
du -sh ~/.turbo

The One-Liner to Check All of Them

Want to see how much space all your package manager caches are consuming? Run this:

echo "=== Package Manager Caches ===" && \
du -sh ~/.npm 2>/dev/null; \
du -sh ~/Library/Caches/Yarn 2>/dev/null; \
du -sh ~/Library/pnpm 2>/dev/null; \
du -sh ~/.bun/install/cache 2>/dev/null; \
du -sh ~/.deno 2>/dev/null; \
du -sh ~/.turbo 2>/dev/null

In my experience, the combined size of these caches ranges from 2-10GB depending on how many different projects and package versions you’ve worked with.

Prevention Tips: Keeping node_modules Under Control

Deleting everything feels great, but it’ll grow back. Here are some strategies to keep node_modules from swallowing your disk again.

Use pnpm Instead of npm

pnpm’s content-addressable store means that if 10 projects use the same version of React, only one copy exists on disk. Each project’s node_modules contains hard links to the central store. In practice, this reduces total disk usage by 50-70% compared to npm.

Switching is straightforward — pnpm uses the same package.json format and can import existing lockfiles:

npm install -g pnpm
pnpm import        # converts package-lock.json to pnpm-lock.yaml
pnpm install       # creates a linked node_modules

Configure .npmrc for Smaller Installs

Add these to your ~/.npmrc to reduce what gets installed:

# Don't install optional dependencies (often native binaries you don't need)
optional=false

# Disable package-lock generation for throwaway projects
# (only use this for experiments, not real projects)
# package-lock=false

Clean Up Regularly

Set a reminder to clean node_modules every month or two. Or, if you want to remember which projects are stale, use ls -la on your project directories and sort by modification date:

# List projects by last modification date
ls -lt ~/projects/*/package.json 2>/dev/null | head -20

Don’t Forget Build Artifacts

JavaScript build tools generate output directories that are just as safe to delete as node_modules. Common ones include:

  • dist/ — Vite, Rollup, webpack, esbuild
  • build/ — Create React App, various tools
  • .next/ — Next.js build cache and output
  • .nuxt/ — Nuxt.js build output
  • out/ — Next.js static export, other tools

These regenerate on the next npm run build. If a project is sitting idle, there’s no reason to keep them around.

The Automated Way: Let MegaCleaner Handle It

The command-line approach works, but it has limitations. find is slow on large directory trees, it can’t tell you which projects are stale versus actively in use, and you have to remember to run it. Plus, manually tracking six different cache directories across four package managers gets old.

MegaCleaner is a native macOS app I built specifically for this problem. Its Node.js scanner handles all of the above automatically:

What it finds:

  • Every node_modules folder across all your project directories and external drives
  • Package manager caches: npm (~/.npm), Yarn (~/Library/Caches/Yarn), pnpm (~/Library/pnpm), Bun (~/.bun/install/cache), Deno (~/.deno)
  • Turborepo global build cache (~/.turbo)
  • JS/Web build artifacts (dist, build, .next, .nuxt, out) in any project that has a package.json

What makes it smarter than find:

  • Staleness detection. MegaCleaner checks the modification dates of actual source files in each project (.js, .ts, .tsx, .vue, .svelte, .astro, .json, .css, .scss, and more) — not just the node_modules folder itself. If you haven’t edited source code in a project for months, it marks that project’s node_modules as stale and pre-selects it for cleanup.
  • Project name detection. It reads each project’s package.json to show you human-readable project names instead of raw directory paths.
  • Package manager awareness. It detects which package manager each project uses by checking for lockfiles (bun.lockb, pnpm-lock.yaml, yarn.lock, package-lock.json) and shows you the correct reinstall command (bun install, pnpm install, yarn, or npm install).
  • No nested duplicates. It skips node_modules inside other node_modules folders to avoid double-counting, and follows canonical paths to prevent counting symlinked directories twice.
  • Symlink safety. It skips symbolic links entirely to avoid infinite loops and accidental deletion of linked directories.

Node.js is just one of MegaCleaner’s 29 scanners. It also covers Xcode DerivedData, Docker images, Python virtual environments, Rust target directories, Go module caches, Homebrew leftovers, and more. If you’re a polyglot developer, the savings add up fast.

MegaCleaner is a one-time purchase: $49, no subscription. It’s a native macOS app — no Electron, no web views.

Download MegaCleaner

Quick Reference: Commands Checklist

Here’s everything from this article in one place. Bookmark this section.

Find all node_modules and their sizes:

find ~ -name "node_modules" -type d -maxdepth 5 -exec du -sh {} \; 2>/dev/null

Delete all node_modules:

find ~ -name "node_modules" -type d -maxdepth 5 -exec rm -rf {} + 2>/dev/null

Clean npm cache:

npm cache clean --force

Clean Yarn cache:

yarn cache clean

Prune pnpm store:

pnpm store prune

Delete Bun cache:

rm -rf ~/.bun/install/cache

Check all cache sizes at once:

du -sh ~/.npm ~/Library/Caches/Yarn ~/Library/pnpm ~/.bun/install/cache ~/.deno ~/.turbo 2>/dev/null

JavaScript’s dependency model means node_modules will always come back. The key is not to let it sit around consuming space in projects you’re not actively working on. Whether you set up a monthly terminal ritual or let MegaCleaner handle it automatically, your Mac’s storage will thank you.