node_modules and developer caches on a Mac
Forty repositories quietly hold a hundred gigabytes. Where it accumulates, which directories are truly disposable, and how to clear them.
9 minutters lesing · Oppdatert 8. september 2026
Artiklene våre skrives bare på engelsk. Appen og resten av nettstedet er fullt oversatt.
The arithmetic
A single modern front-end project is 300–800 MB in node_modules. A Rust project with a debug and a release profile is 1–4 GB in target/. A Python project with a virtual environment and compiled wheels is 200 MB–2 GB. None of these is alarming on its own.
The problem is multiplication. Forty repositories in ~/code, half of which you have not opened in a year, is routinely 60–120 GB of directories that a single command each would recreate. It is the largest reclaimable category on most developer machines, and it is invisible in the Storage panel because every byte of it lands in "System Data" or "Documents".
Find yours first. This lists every node_modules directory with its size, largest first:
find ~ -type d -name node_modules -prune -print0 2>/dev/null \
| xargs -0 du -sh 2>/dev/null | sort -rh | head -30
# Same idea for Rust and Python
find ~ -type d -name target -maxdepth 6 -prune -print0 2>/dev/null | xargs -0 du -sh | sort -rh | head
find ~ -type d -name .venv -prune -print0 2>/dev/null | xargs -0 du -sh | sort -rh | head-prune stops the search descending into a match, which both speeds it up enormously and avoids matching nested node_modules inside node_modules.
What is genuinely disposable
The test is simple: if a checked-in manifest and one command recreate the directory exactly, it is disposable. That holds for all of these.
- node_modules — next to a package.json. Recreated by npm/pnpm/yarn install.
- target/ — next to a Cargo.toml. Recreated by cargo build. Usually the largest single offender per project.
- .next/, dist/, build/, out/, .turbo/, .parcel-cache/, .nuxt/, .svelte-kit/ — framework build output.
- .venv/, venv/, __pycache__/, .pytest_cache/, .mypy_cache/, .ruff_cache/ — Python environments and caches. Recreated from requirements.txt, pyproject.toml or a lock file.
- Pods/ — CocoaPods dependencies, next to a Podfile.lock. Recreated by pod install.
- vendor/ — Composer or Go vendor directories, recreated from their lock files.
- build/ and .gradle/ in Android projects; DerivedData for iOS (see the Xcode article).
- coverage/, .nyc_output/, storybook-static/ — generated reports.
The qualifier matters: a directory named target with no Cargo.toml beside it may be someone's actual work. Always check for the sibling manifest before deleting.
The shared caches, and the right command for each
Separately from per-project directories, every package manager keeps a global cache in your home folder. These are shared across all projects and are usually 5–40 GB in total. Each has a supported prune command that is safer than deleting the directory, because it leaves the store's index consistent.
pnpm store prune # ~/Library/pnpm/store
npm cache clean --force # ~/.npm/_cacache
yarn cache clean # ~/Library/Caches/Yarn
cargo cache -a # ~/.cargo/registry, needs cargo-cache
go clean -modcache # ~/go/pkg/mod
pip cache purge # ~/Library/Caches/pip
uv cache clean # ~/Library/Caches/uv
brew cleanup --prune=all # ~/Library/Caches/Homebrew
docker system prune -a # Docker images, containers, build cache
rm -rf ~/Library/Caches/ms-playwright # browser binaries, re-downloaded on demandpnpm is content-addressed and hard-links into projects. Pruning the store while projects still reference it is fine — prune only removes unreferenced content — but deleting the store directory outright will break every existing node_modules that links into it.
A sweep you can actually run
The pattern below deletes node_modules only from projects untouched for six months, which is the version of this that does not interrupt your week. Read it before running it: it deletes without a Trash step, so start by removing the `-exec` line and looking at the list.
The same shape works for target/ (test for Cargo.toml) and .venv (test for pyproject.toml).
# 1. LOOK FIRST — no deletion
find ~/code -type d -name node_modules -prune -mtime +180 -print
# 2. Only when the list is right
find ~/code -type d -name node_modules -prune -mtime +180 -exec rm -rf {} +
# Rust equivalent, via cargo so it only touches real crates
find ~/code -name Cargo.toml -maxdepth 3 -execdir cargo clean \;mtime on a directory reflects when its immediate contents last changed, which for node_modules is the last install — a good proxy for "this project is dormant", not a perfect one.
What not to delete
Do not delete .git. It is the repository, not a cache; if the branch you are on has unpushed commits, they are gone. Do not delete lock files (package-lock.json, pnpm-lock.yaml, Cargo.lock, Podfile.lock) — they are small and they are what makes the reinstall reproducible.
Do not delete .env files or anything under a config/ directory to save space; they are bytes and they cost hours. And do not delete a directory just because it matches a pattern: check for the sibling manifest that proves it is regenerable.
Two more that look disposable and are not. A directory named build/ in a project with no build system is often somebody's actual output that was never checked in — CAD exports, rendered video, a compiled binary a colleague sent you. And .venv in a project whose requirements file has drifted may not reinstall cleanly at all: if the environment was assembled by hand over months, deleting it can cost an afternoon of dependency archaeology to rebuild. Check that `pip install -r requirements.txt` or `uv sync` actually reproduces it before you rely on being able to.
The same caution applies to any project you are mid-way through debugging. A build directory is only regenerable if the build currently works; if you are halfway through a migration and the build is red, that directory holds the last artifacts that ran. Finish the work, then clean.
Container and virtual machine images
The largest single item on many developer Macs is not a project directory at all. It is a virtual disk.
Docker Desktop stores everything — images, containers, volumes and build cache — inside one sparse disk image at ~/Library/Containers/com.docker.docker/Data/vms. That file grows as you pull images and does not shrink when you delete them: deleting a container returns space inside the virtual disk, not on your Mac. `docker system df` shows what is reclaimable, `docker system prune -a --volumes` reclaims it inside the VM, and Docker Desktop then has to be told to compact the disk image (Settings → Resources → Advanced). Note that `--volumes` deletes named volumes, which is where databases keep their data; read the prompt.
Colima, OrbStack, Podman, Parallels, VMware Fusion, UTM and the Android emulator all have the same shape: one big file that grows monotonically. If you have ever run a VM on the machine, look for it before doing anything else — a single forgotten Windows image is often 60 GB.
Xcode's simulators are the exception: they are ordinary directories rather than disk images, which is why the Xcode article can recommend deleting them directly.
docker system df
docker system prune -a # images, containers, build cache
du -sh ~/Library/Containers/com.docker.dockerMaking it a habit rather than an emergency
The reason this becomes a 100 GB problem is that there is no natural moment to clean it up. Two things help: run the dormant-project sweep quarterly, and prune the global package-manager caches at the same time. Between them that is five minutes and usually tens of gigabytes.
Dropit recognises these directories structurally rather than by name alone — node_modules only when there is a package.json beside it, target/ only next to a Cargo.toml — and groups them per project with sizes and last-modified dates, so a dormant repository is obvious. Every row carries the reason it is safe ("rebuilt by pnpm install") rather than asking you to take it on trust. The scan and the whole catalogue are free to look at; staging a selection and sending it to the Trash is the paid part.
Spørsmål
Is it safe to delete node_modules?
Yes, when there is a package.json and a lock file in the same directory. Running the install command again reproduces it exactly.
How do I find all node_modules folders on a Mac?
Use `find ~ -type d -name node_modules -prune -print0 | xargs -0 du -sh | sort -rh`. The -prune flag stops the search descending into matches, which makes it fast.
How much space do developer caches use?
On an active machine, commonly 40–120 GB across per-project directories and the shared caches for npm, pnpm, cargo, Go, pip, Homebrew and Docker.
Should I delete the pnpm store?
Prune it, do not delete it. `pnpm store prune` removes unreferenced content; deleting the directory breaks every existing node_modules that hard-links into it.
Få plassen tilbake i kveld.
Én betaling. Alle fremtidige oppdateringer inkludert. Fungerer på to av Mac-ene dine.
Last ned