A cleanup script for developers that shows first and moves to the Trash
One script that sizes every regenerable developer cache on a Mac, prints a report, and only moves things to the Trash when you ask. Every path explained.
Cleanup scripts found online usually do the dangerous thing: rm -rf on a long list of paths, run blind. This one does the opposite. By default it only measures and prints. With --trash it moves each folder to the Trash, so any mistake is one drag away from being undone.
The script
#!/usr/bin/env bash
# dev-clean.sh: size developer caches; with --trash, move them to the Trash.
set -u
MODE=${1:-report}
PATHS=(
"$HOME/.npm/_cacache"
"$HOME/.npm/_npx"
"$HOME/Library/Caches/Yarn"
"$HOME/.yarn/berry/cache"
"$HOME/Library/pnpm/store"
"$HOME/Library/Caches/pnpm"
"$HOME/.bun/install/cache"
"$HOME/Library/Caches/node-gyp"
"$HOME/.cache/node/corepack"
"$HOME/Library/Caches/ms-playwright"
"$HOME/.gradle/caches"
"$HOME/.cargo/registry/cache"
"$HOME/Library/Caches/pip"
"$HOME/.cache/uv"
"$HOME/Library/Caches/Homebrew"
"$HOME/Library/Developer/Xcode/DerivedData"
"$HOME/Library/Caches/CocoaPods"
"$HOME/.expo"
)
total=0
for p in "${PATHS[@]}"; do
[ -e "$p" ] || continue
kb=$(du -sk "$p" 2>/dev/null | cut -f1)
total=$((total + kb))
printf '%8.1f MB %s\n' "$(echo "$kb/1024" | bc -l)" "$p"
if [ "$MODE" = "--trash" ]; then
mv "$p" "$HOME/.Trash/$(basename "$p")-$(date +%s)"
fi
done
printf '\n%8.1f GB total\n' "$(echo "$total/1048576" | bc -l)"
if [ "$MODE" = "--trash" ]; then
echo "Moved to the Trash. Empty it to free the space."
fiUsing it
chmod +x dev-clean.sh
./dev-clean.sh # report only
./dev-clean.sh --trash # move to the TrashWhat is on the list, and why
Only folders that the owning tool recreates by downloading or building again. Nothing that holds your work, settings or credentials:
| Path | Rebuilt by | Guide |
|---|---|---|
~/.npm/_cacache, ~/.npm/_npx | npm, npx | npx cache |
| Yarn, pnpm, Bun stores | the next install | Yarn and pnpm |
| node-gyp, Corepack | native builds | native module caches |
| Playwright browsers | npx playwright install | Playwright |
| Gradle and Cargo caches | the next build | Gradle |
| pip and uv caches | the next install | uv |
| Homebrew downloads | brew install | Homebrew cache |
| DerivedData, CocoaPods | the next Xcode build | DerivedData |
What is deliberately not on it
- Runtime versions (nvm, rustup, JDKs): removing the one you use breaks your setup. Remove old ones by name.
- node_modules in projects: safe, but better done per project, since an active project will need a full reinstall.
- AI tool sessions and databases: they are history and data, not cache.
- Docker: use
docker system prune, which knows what is in use.
Moving to the Trash means the space only returns once you empty it, which is the point: you can check nothing broke first. A monthly habit around it is in a monthly Mac cleanup routine, and one-line commands for the rest in terminal commands to free space.
Related: Developer in Mac storage.
Related: CMake build folders and ccache and vcpkg build trees.
Common questions
Is there a safe script to clear developer caches on a Mac?
Yes. The script in this guide reports sizes by default and, with --trash, moves each cache to the Trash instead of deleting it.
Which developer folders are safe to delete on a Mac?
Package caches, build caches and downloaded browsers or headers: npm, Yarn, pnpm, Gradle, Cargo registry, pip, uv, Homebrew downloads and Xcode DerivedData.
Why move caches to the Trash instead of rm -rf?
So a mistake can be undone. The space returns when you empty the Trash, after you have checked your tools still work.
Should a cleanup script delete node_modules?
Better not automatically. It is safe, but an active project then needs a full reinstall, so it is better done per project.