Xcode cleanup script vs CleanMyDev: which one actually reclaims 100+ GB safely?

Xcode cleanup script vs CleanMyDev compared on coverage, safety, and rollback. The shell script reclaims fast. CleanMyDev shows receipts before touching DerivedData, Archives, or simulators.

8 min read · Published · Updated · Saad Belfqih

Jonathan Spooner's Reclaim 100+ GB from Xcode landed in iOS dev circles with a title that doubled as a confession: "The Cleanup Script I Wish I'd Written Years Ago." Every working iOS engineer recognised the shape. You write a five line rm -rf script after the third time Xcode refuses to build because the disk is full, alias it to xcleanup, and pass it around for a decade. This post answers whether a hand-rolled Xcode cleanup script is still enough in 2026, or whether the same problem now calls for a GUI like CleanMyDev with receipts and a Trash window.

TL;DR
An Xcode cleanup script is a 30 line shell file that `rm -rf`s `DerivedData`, `Archives`, `iOS DeviceSupport`, `XCTestDevices`, and `CoreSimulator` caches. It reclaims 100+ GB in seconds with zero install. CleanMyDev runs the same paths plus 20 other categories of AI and container junk, shows per-row receipts before deletion, and defaults to Move to Trash with a seven day rollback window. Read your script line by line and ship it to CI, keep it. For the laptop where one bad path nukes a release archive, CleanMyDev pays for itself the first time you `cmd Z` a deletion.

What does a typical Xcode cleanup script actually do?

Most personal Xcode cleanup scripts converge on the same six paths. Here is the canonical shape, derived from Spooner's writeup and the Apple Discussions thread on rogue simulators where engineers post their cleanup commands as forum replies.

#!/usr/bin/env bash
# xcleanup, the script every iOS dev rewrites eventually.
set -euo pipefail

echo "Pre-clean disk:"
df -h /

# 1. DerivedData. Xcode rebuilds it from source on next build.
rm -rf ~/Library/Developer/Xcode/DerivedData/*

# 2. Archives. Only safe if you have already uploaded the build.
rm -rf ~/Library/Developer/Xcode/Archives/*

# 3. iOS DeviceSupport. Re-fetched the first time you attach the device again.
rm -rf ~/Library/Developer/Xcode/"iOS DeviceSupport"/*

# 4. XCTestDevices. Recreated on next `xcodebuild test`.
rm -rf ~/Library/Developer/XCTestDevices/*

# 5. CoreSimulator caches. Safe. Devices folder is not touched.
rm -rf ~/Library/Developer/CoreSimulator/Caches/*

# 6. Unavailable simulator runtimes. The official knob.
xcrun simctl delete unavailable

echo "Post-clean disk:"
df -h /

The script is fast, idiomatic, and dangerous the way every long-lived shell script is dangerous. No dry run. No path validation. The Archives line is one typo away from rm -rf ~/Library/Developer/Xcode/, which wipes every project archive on that Mac. The cleanupPeriodDays safety net Anthropic shipped after the Claude Code 472 GB blowup does not exist for Xcode. Apple's xcrun simctl delete unavailable ignores the rogue runtimes in /System/Library/AssetsV2 that the Apple Developer Forums thread 812992 documented at 9 GB on a single Mac.

How does CleanMyDev approach the same cleanup?

CleanMyDev was written by an iOS dev who shipped exactly this kind of script for five years before building the GUI. The Xcode paths it audits are a strict superset of what a personal script touches.

Category Path In a typical Xcode cleanup script In CleanMyDev
DerivedData ~/Library/Developer/Xcode/DerivedData/ yes, rm -rf yes, Move to Trash
Archives ~/Library/Developer/Xcode/Archives/ yes, often unconditional yes, with upload-status warning
iOS DeviceSupport ~/Library/Developer/Xcode/iOS DeviceSupport/ yes yes, per-device row
watchOS DeviceSupport ~/Library/Developer/Xcode/watchOS DeviceSupport/ sometimes yes
XCTestDevices ~/Library/Developer/XCTestDevices/ yes yes
CoreSimulator caches ~/Library/Developer/CoreSimulator/Caches/ yes yes, four subfolders separately
CoreSimulator devices ~/Library/Developer/CoreSimulator/Devices/ rarely, risky yes, opt-in per device
Unavailable runtimes xcrun simctl delete unavailable yes yes, called via API
Orphaned AssetsV2 runtimes /System/Library/AssetsV2/com_apple_MobileAsset_iOSSimulatorRuntime/ no yes, audit-first
Module cache ~/Library/Developer/Xcode/UserData/IB Support/ no yes
SPM cache ~/Library/Caches/org.swift.swiftpm/ sometimes yes
SwiftLint cache ~/Library/Caches/SwiftLint/ no yes
Xcode previews ~/Library/Developer/Xcode/UserData/Previews/ no yes
Xcode crash logs ~/Library/Logs/DiagnosticReports/Xcode_* no yes

The script does the obvious five. CleanMyDev does the obvious five plus the eight nobody remembers, plus a read-only audit with size and last-modified date before any deletion.

Which one is actually safer?

A Mac cleaner is safe when four properties hold: it shows the path before touching it, deletion is reversible, credentials and source are out of scope, and a typo cannot escalate scope. A typical script passes the third because the author wrote it, and fails the other three. CleanMyDev passes all four by design.

Safety property Xcode cleanup script CleanMyDev
Shows path and size before deletion no, prints df only yes, per row
Reversible (Trash, snapshot, or undo) no, rm -rf is permanent yes, Move to Trash with seven day window
Excludes credentials and source yes, if you wrote it carefully yes, hardcoded denylist for ~/.ssh, ~/.aws, ~/.gnupg, project .git
Dry run mode rare, requires editing the script yes, audit-only is the default
Avoids sudo depends yes, never escalates
Per-build CI variant yes, that is what scripts are for not the target

A script is safe in proportion to how recently you read it. A script that has lived in your dotfiles for six years through three macOS upgrades is a loaded foot-gun. The brtkwr "Using Claude to free 200GB" writeup makes the case directly: "Docker was the biggest culprit. The volumes were almost entirely unused, probably from old postgres/redis containers I'd stopped months ago." A pure Xcode script would have missed every byte of that 108 GB. A GUI auditor surfaces it on the first scan.

How much disk does each one actually reclaim?

The Xcode subset is the easy win. The interesting comparison is what the script leaves behind. Numbers below come from the 16-month AI tools disk footprint audit on a 1 TB MacBook Pro after six uncleaned months.

Category Reclaimed by Xcode cleanup script Reclaimed by CleanMyDev (same Mac)
DerivedData 31 GB 31 GB
Archives 12 GB 12 GB
iOS DeviceSupport 22 GB 22 GB
CoreSimulator caches 18 GB 18 GB
XCTestDevices 6 GB 6 GB
Orphaned AssetsV2 runtimes 0 GB 14 GB
SPM cache 0 GB 4 GB
Xcode previews 0 GB 2 GB
Claude Code debug + MCP logs 0 GB 47 GB
Cursor packfiles 0 GB 9 GB
Codex sessions and rollouts 0 GB 8 GB
Docker volumes 0 GB 38 GB
Ollama and Hugging Face models 0 GB 22 GB
Total 89 GB 233 GB

A clean script reclaims 89 GB in under a minute. CleanMyDev reclaims 233 GB across the same minute on the Xcode subset plus another 10 minutes of review on the AI and Docker rows. The script wins on speed. CleanMyDev wins on coverage.

What does the CleanMyDev workflow replace, exactly?

The audit-and-trash flow replaces three things: the script, the second-guessing about whether the script took something useful, and the monthly ritual of adding one more du -sh line for the new tool eating disk.

# What CleanMyDev runs under the hood, exposed as a CLI for transparency.
# 1. Audit mode. Read-only. Prints sizes for every known cache path.
cleanmydev audit --json > ~/Desktop/cleanmydev-audit.json

# 2. Review the JSON. Each row has: path, size, last_modified, owning_tool,
#    risk_label ("safe" | "rebuilds" | "redownloads" | "credentials" | "danger").
jq '.[] | select(.size_bytes > 1000000000)' ~/Desktop/cleanmydev-audit.json

# 3. Selective trash. Same paths the script uses, but reversible.
cleanmydev clean \
  --include xcode.deriveddata \
  --include xcode.devicesupport \
  --include xcode.archives \
  --include xcode.coresim.caches \
  --include xcode.coresim.runtimes \
  --trash

# 4. Recover from regret. Items live in Trash for seven days by default.
open ~/.Trash

A script does the third step. CleanMyDev does all four. The audit matters when the same Mac runs Claude Code, Cursor, Codex, Ollama, and Docker, because the Xcode bytes are the smallest pile in 2026. The which-AI-coding-tool-uses-most-disk ranking puts Claude Code MCP logs at 47 GB, more than DerivedData plus Archives combined.

Which one should you pick?

Use this decision matrix.

Your situation Pick
You ship CI builds and need a non-interactive cleanup step Xcode cleanup script
You cannot install third-party apps on a managed Mac Xcode cleanup script
You wrote the script yourself in the last six months and read every line Xcode cleanup script
You want one tool that audits Xcode plus AI plus Docker plus JS caches CleanMyDev
You want a Trash window in case you rm -rf the wrong path CleanMyDev
You want a per-row size and last-modified before any deletion CleanMyDev
Your Mac is on the edge of disk full and you do not have time to debug a script CleanMyDev
You want both run the script on CI, run CleanMyDev on the laptop

The script wins on automation. The GUI wins where a typo costs you a release archive. The two are not exclusive and most iOS engineers will keep both.

Is the script enough in 2026?

Five years ago a personal Xcode cleanup script was enough because the Xcode caches were the whole story. The shape of the dev Mac in 2026 is different. The Claude Code 472 GB postmortem is one data point. The AI coding tools disk footprint explainer puts the AI category at 60+ GB on the median working Mac. A script that only knows about ~/Library/Developer/Xcode/ is solving last decade's problem.

Run du -sh ~/.claude ~/.codex ~/.cursor ~/.cache/huggingface ~/.ollama 2>/dev/null once. If those five paths add up to more than DerivedData, the script is no longer the right tool. If they do not, keep the script and move on.

If you want one tool that runs the same five Xcode commands plus the 20 other categories that quietly fill a 2026 Mac, CleanMyDev is $9.99 lifetime at /#pricing. Move to Trash by default, no sudo, no account, no telemetry, no renewal. The audit mode is free, so you can run it next to your script and compare what each one finds before paying. The script stays available if it covers enough. CleanMyDev is there if it does not.

Related reading

Stop wondering what System Data is.

CleanMyDev opens the box. 110+ developer-specific cleanup targets. Move-to-Trash by default. $9.99 lifetime.

Get CleanMyDev — $9.99