Your SSD didn't shrink — Xcode's DerivedData, a dozen forgotten node_modules folders, and Docker's virtual disk did the shrinking for you. Almost everything in this guide is safe to delete outright; the real question is never "will this break something," it's "how long is the rebuild, and do I want to spend that bandwidth right now." Below are the exact paths, the exact commands, and what each one actually costs you to undo.
The real question isn't "is this safe" — it's "what does rebuilding cost you"
Every cache in this guide exists because it's regenerable — that's the definition of a cache, not a backup. Xcode rebuilds DerivedData from your source the next time you press Cmd-B. npm re-downloads a package from the registry the next time you run install. Docker re-pulls an image from a registry. None of that risks your Mac or your project. What it costs is time — a slower next build, a slower next install, bandwidth you might not want to spend on hotel wifi. That's the decision to make before running anything below: not "could this break something," but "am I trading gigabytes right now for a slower next hour." Two commands in this guide break that pattern, and they're flagged explicitly where they show up — one deletes a build you genuinely can't recreate, and one can delete a database's actual data instead of a cache.
Xcode: DerivedData, Archives, device support, and simulators
Xcode spreads its disk usage across four places that behave completely differently once you delete them. Treat them the same and you'll either lose an archived build you needed, or leave tens of gigabytes of debug symbols untouched out of unnecessary caution.
DerivedData — the one you'll clear most often
~/Library/Developer/Xcode/DerivedData holds build products, module caches, and per-project indexes for everything you've opened in Xcode. Quit Xcode, then delete it from Finder (press Shift+Command+G to jump straight to the path) or run rm -rf ~/Library/Developer/Xcode/DerivedData/* in Terminal. Cost to undo: none beyond a slower next build — Xcode has to reindex the project and recompile from scratch instead of incrementally, which on a large app can mean minutes instead of seconds.
Archives — the one exception in this whole guide
~/Library/Developer/Xcode/Archives stores the actual .xcarchive bundles from every Archive build you've made for TestFlight or the App Store. Unlike everything else here, an archive isn't a cache of your source — it's a specific, timestamped binary you can't regenerate identically once your code has moved on, since a rebuild today won't byte-for-byte match a build from six months ago. Delete this folder freely for hobby projects and internal tools. For anything currently live on the App Store, keep at least the archive for your shipping version — you'll want it if you ever need to re-export a dSYM to symbolicate a crash report from that exact build.
iOS DeviceSupport — debug symbols for a device you plugged in once
~/Library/Developer/Xcode/iOS DeviceSupport holds a subfolder per iOS version any physical device has run while connected to your Mac, so Xcode can symbolicate crash logs and debug on-device. Xcode never deletes old ones itself, so a few years of testing on inherited or upgraded phones leaves you with version folders for iOS releases nobody runs anymore. Delete individual version subfolders you don't need, or the whole folder. Cost to undo: reconnect a device running that iOS version and Xcode re-downloads its symbols automatically — a few hundred megabytes and a couple of minutes, not a rebuild.
Simulators: three different things sharing one name
"Simulator cleanup" actually covers three unrelated pieces of storage, with different tools for each. Simulator devices — the specific virtual iPhones and iPads you've created — sometimes point at a runtime an Xcode update already removed. Clear the orphaned ones with xcrun simctl delete unavailable; there's nothing to rebuild, they were already broken. Simulator runtimes — the actual OS disk images, installed from Xcode > Settings > Platforms per Apple's own instructions — are the multi-gigabyte part. List what's installed with xcrun simctl runtime list, then remove anything you're not actively testing with xcrun simctl runtime delete unavailable, or more aggressively with xcrun simctl runtime delete --notUsedSinceDays 365. Cost to undo: re-downloading that runtime from Xcode > Settings > Platforms, which for a single iOS runtime is a multi-gigabyte download over your own connection. Simulator caches at ~/Library/Developer/CoreSimulator/Caches — mostly dyld shared-cache files — regenerate the next time you boot a simulator, and cost nothing to clear.
node_modules: the real problem isn't one folder, it's forty of them
A single node_modules folder is rarely the issue — it's the twenty side projects, tutorials, and cloned repos you haven't opened in a year, each still holding its own full dependency tree. Deleting any of them is entirely safe: node_modules is derived completely from package.json and a lockfile, and npm install, yarn install, or pnpm install rebuilds it exactly. The cost is time and bandwidth on the next install — nothing here breaks a project unless the lockfile itself is gone too.
Finding all of them by hand is the tedious part. npkill — run with npx npkill, no install needed — walks your filesystem, lists every node_modules folder with its size, and deletes the ones you pick with a keypress, flagging folders that look like they belong to a project you're mid-way through.
Each package manager also keeps its own separate download cache, which is a different thing to clean:
- npm caches downloaded packages at
~/.npm/_cacache. Clear it withnpm cache clean --force— the--forceflag exists because npm treats a direct cache clear as an unsupported operation, not because it's actually risky. Cost to undo: the next install re-downloads whatever it needs from the registry. - pnpm keeps one shared content-addressable store instead of a per-project cache, at
~/Library/pnpm/store/v3on current installs (older setups may still use~/.pnpm-store/v3— check yours withpnpm store path). Runpnpm store pruneto remove only packages no project on your Mac references anymore. Cost to undo: a project that needs a pruned package re-fetches it on its next install. - Yarn Classic (v1) caches at
~/Library/Caches/Yarn; clear it withyarn cache clean. Yarn Berry (v2+) defaults to a per-project.yarn/cacheplus a global cache at~/.yarn/berry/cache; clear the global one withyarn cache clean --all. Cost to undo: same shape as the others — a slower next install, not a broken one.
Docker: why docker system prune doesn't actually shrink anything on your Mac
Start with docker system df — it prints exactly how much space images, containers, local volumes, and build cache are using, and how much Docker considers reclaimable. docker system prune then removes stopped containers, unused networks, dangling (untagged) images, and unused build cache, but it deliberately leaves tagged images alone. For that, you need docker system prune -a, which removes every image with no container — running or stopped — still associated with it, not just the dangling ones. Docker's own docs spell out exactly what each variant removes.
One flag here needs a more precise warning than "be careful": docker system prune --volumes (or -a --volumes) only removes anonymous volumes that no container — running or stopped — still references, per Docker's own CLI reference. A stopped Postgres or Redis container still counts as referencing its volume, so --volumes alone won't touch it. The real danger shows up a step later: run docker rm on that container — a completely ordinary cleanup step — and its anonymous volume is now orphaned, referenced by nothing. The next docker system prune --volumes you run treats it as unused and deletes it, taking whatever it held with it. Named volumes get an extra layer of protection on top of that: removing one at all takes docker volume prune --all or docker volume rm by name, not --volumes on system prune — and even then, only once no container still references it. Run docker volume ls and know what's actually attached before you prune anything.
Now the gotcha that actually eats disk space on Apple Silicon Macs: Docker Desktop stores every image, container, and volume inside one virtual disk file, at ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw. It's a sparse file — it grows as you pull images, but pruning data inside it doesn't shrink the file on your Mac. Run docker system prune -a --volumes, watch docker system df report gigabytes freed, and Docker.raw can still show 60 GB in Finder. To actually get that space back on disk, lower the size limit in Docker Desktop's Settings > Resources > Advanced (Docker compacts the file down toward what's actually in use), or, if that's not enough, reset Docker Desktop to factory defaults — which deletes every image, container, and volume and rebuilds the file from nothing. That reset is the single most expensive rebuild in this whole guide: every image gets re-pulled from a registry, over a network connection, not a local cache. (Docker's disk image is one of the largest things macOS's Storage settings lump under "System Data" — see our explainer on what's actually inside System Data for the rest of what's hiding in there.)
The rest of the toolchain: CocoaPods, Gradle, Cargo, Homebrew, pip and uv
None of these move the needle the way Xcode and Docker do, but a few years of a laptop's life adds them up, and each has its own path and its own command.
- CocoaPods caches downloaded pod sources at
~/Library/Caches/CocoaPods.pod cache clean --allclears it;pod cache listshows what's in there first. Cost to undo: the nextpod installre-downloads whatever it needs. - Gradle (Android projects) keeps its biggest footprint at
~/.gradle/caches. Stop any running daemons first with./gradlew --stop, then it's safe to delete. Cost to undo: your next Gradle sync re-downloads every dependency — on a large Android project, genuinely slow, so clear this between projects, not mid-sprint. - Cargo (Rust) keeps downloaded crate sources and metadata at
~/.cargo/registry, plus checked-out git dependencies at~/.cargo/git. Both are safe to delete;cargo buildre-fetches whatever yourCargo.lockneeds. - Homebrew keeps downloaded bottles and cask installers at
~/Library/Caches/Homebrew.brew cleanuponly removes files older than 120 days by default; add--prune=allto remove everything regardless of age. Cost to undo: reinstalling or rolling back a formula soon after re-downloads it. - pip caches wheels at
~/Library/Caches/pip; clear it withpip cache purge. uv, the newer Python package manager from Astral, caches at~/Library/Caches/uvby default; runuv cache clean, oruv cache pruneto remove only unused entries. Cost to undo, both: the next install re-downloads the package.
The cache-to-path cheat sheet
Everything above, in one table, for when you just want the path and the verdict.
| Cache | Path | Safe to delete? | Cost to restore |
|---|---|---|---|
| Xcode DerivedData | ~/Library/Developer/Xcode/DerivedData | Yes, always | Slower next build (full recompile) |
| Xcode Archives | ~/Library/Developer/Xcode/Archives | Only builds you'll never re-symbolicate | Not rebuildable — a point-in-time binary |
| iOS DeviceSupport | ~/Library/Developer/Xcode/iOS DeviceSupport | Yes, for OS versions you're not testing | Re-downloads on next device connect (minutes) |
| Simulator runtimes | Managed via Xcode > Settings > Platforms; check with xcrun simctl runtime list | Yes, for runtimes you're not testing | Multi-GB re-download from Xcode |
| Simulator dyld cache | ~/Library/Developer/CoreSimulator/Caches | Yes, always | Regenerates on next simulator boot |
| node_modules (per project) | Inside each project folder | Yes, always | Re-download on next install |
| npm cache | ~/.npm/_cacache | Yes, always | Re-download on next install |
| pnpm store | ~/Library/pnpm/store/v3 | Yes — prune only removes orphans | Re-fetch on next install |
| Yarn cache | ~/Library/Caches/Yarn (Classic) / ~/.yarn/berry/cache (Berry) | Yes, always | Re-download on next install |
| Docker images/containers | Inside Docker.raw: ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw | Yes, via docker system prune -a | Re-pull from a registry; rebuild containers |
| Docker anonymous volumes | Same Docker.raw file | Only after their container has been removed (docker rm) — --volumes then treats them as unused | None, if it held real data |
| Docker named volumes | Same Docker.raw file | Only via docker volume prune --all or docker volume rm, and only once no container still references them | None, if it held real data |
| CocoaPods cache | ~/Library/Caches/CocoaPods | Yes, always | Re-download on next pod install |
| Gradle caches | ~/.gradle/caches | Yes, always | Re-download all dependencies on next sync |
| Cargo registry/git | ~/.cargo/registry, ~/.cargo/git | Yes, always | Re-fetch crates on next build |
| Homebrew cache | ~/Library/Caches/Homebrew | Yes, always | Re-download if you reinstall soon after |
| pip / uv cache | ~/Library/Caches/pip, ~/Library/Caches/uv | Yes, always | Re-download on next install |
Tools already built for this — and why we're building SwoopByte Disk differently
This isn't an empty niche. Search for a dev-focused Mac cleaner and you'll run into a few of these already:
- DeepClean ($39 one-time for one Mac, $59 for three) bills itself as the deepest developer scanner in the category — its own comparison page claims 17+ developer tools, including Xcode, npm, Docker, Gradle, and JetBrains. That breadth checks out against its own product page, and to its credit, the same page asks readers to "take our own rating with appropriate skepticism" — a more honest disclosure than most vendor comparison pages bother with.
- CodeCleaner is free to scan with no account required, dev-only by design, and covers a similarly wide list — Xcode, Cargo/Rustup, Docker/Colima, npm/yarn/pnpm, pip/Poetry/Conda, Gradle/Android — using what it calls whitelist-based deletion, so it only ever touches known regenerable build artifacts, never source.
- ClearDisk is free, open-source under MIT, sitting at 548 GitHub stars as of this writing, and scans 63 developer cache paths with a genuinely verifiable zero-network, zero-telemetry claim — the strongest privacy story of the four, if a smaller, community-maintained project works for you.
- DevCleaner runs the pricing model closest to ours: free forever for scanning and cleanup, with a $29 lifetime or $19.99/year Pro tier that adds scheduling and automation, not more detection.
All four are single-purpose — they find and clear developer caches, full stop. None is also a general disk visualizer, a duplicate finder, or an app uninstaller. Want a plain map of your whole disk, a System Data breakdown that names what "Other" actually is, and a way to remove an app you no longer use, and you're running two or three separate tools instead of one.
That's the gap SwoopByte Disk is built to close. Its free tier covers the general disk map — the scan, the Space Map, largest files and folders, a category breakdown, and a System Data breakdown that names Docker's disk image specifically, with a real size, next to Time Machine local snapshots and stale iPhone backups. Duplicate detection is free too. Batch dev-cache cleanup, System-Data reclaim actions, and scan history are a one-time $14.99 Pro unlock, not a subscription — detection itself is never behind the paywall.
One more distinction none of the four tools above draws: clearing a cache and removing a toolchain are different jobs. If you've fully moved off Docker, or nvm, or a Homebrew-installed Node, you don't want its cache cleared — you want it gone. That's SwoopByte Uninstaller's job, not Disk's: it detects and sizes whole dev toolchains (Homebrew, Node .pkg installs, nvm, pyenv, Rust, Docker) for free, and actually removing them is a one-time $12.99 Pro unlock. Disk reclaims space from a toolchain you're keeping; Uninstaller removes one you're not. Every removal in both apps goes to the Trash, never straight to permanent deletion.
How often you actually need to do this
DerivedData, abandoned node_modules folders, and package-manager caches are safe to clear on a schedule — monthly, or whenever a build feels slow — and cost nothing but a little rebuild time. Docker.raw and simulator runtimes are different: touch those only when you're actually short on space, since the rebuild (a multi-gigabyte re-pull or re-download) is real enough to notice. Xcode Archives aren't a routine cleanup item at all — decide per build, not on a timer, whether you'll ever need to re-symbolicate it.
FAQ
Is it safe to delete Xcode's DerivedData folder?
Yes. DerivedData is rebuilt entirely from your project source the next time you build. The only cost is a slower first build afterward, since Xcode has to reindex and recompile from scratch instead of incrementally.
Does deleting node_modules break anything?
No, as long as package.json and a lockfile still exist. Running npm install, yarn install, or pnpm install rebuilds node_modules exactly — the only real cost is the time and bandwidth of re-downloading everything.
Why doesn't docker system prune shrink Docker Desktop's disk usage on my Mac?
Because Docker Desktop stores everything inside one sparse virtual disk file, Docker.raw, that grows but doesn't automatically shrink. Pruning frees space inside that file, not the file itself — you need to lower Docker Desktop's disk image size limit (Settings > Resources > Advanced) or reset it to reclaim space on your actual drive.
Can docker system prune delete my database's data?
Only in a specific sequence: --volumes alone won't touch a volume whose container still exists, even stopped, but if you've already removed that container with docker rm, its anonymous volume is orphaned and the next --volumes prune deletes it with whatever it held. Named volumes need the separate docker volume prune --all (or docker volume rm) to be removed at all. Run docker volume ls before you prune anything, so you know what's actually there.
Is it safe to delete the iOS Simulator's DeviceSupport files?
Yes. Xcode automatically re-downloads the debug symbols for any iOS version the next time you connect a physical device running it — a few hundred megabytes and a couple of minutes, not a rebuild.
Do I need a dedicated dev-cleanup tool, or are the manual commands enough?
The manual commands above cover everything safely on their own. A dedicated tool mainly saves you the trouble of remembering every path and running each command by hand — worth it if you're doing this across a lot of projects and toolchains, unnecessary if you only ever touch Xcode and node_modules occasionally.
Related guides
What is System Data on a Mac, and why won't it shrink?
What's actually inside System Data, why the number moves on its own, and how to shrink it safely.
Read guide →What is safe to delete on a Mac?
The full breakdown of what's safe to remove on a Mac, what deserves a second look, and what to never touch.
Read guide →How to completely uninstall an app on Mac
Why dragging an app to the Trash leaves files behind, and how to remove the rest safely.
Read guide →