Coding agents that work in parallel usually give each task its own git worktree, so one agent's edits can't collide with another's. Claude Code, for example, creates them under .claude/worktrees/ in your repository. Source code is small. The build output each worktree produces is not, and every worktree builds its own. Here is why it adds up, how to measure it and how to keep it down.
A worktree is a separate checkout of the same repository in its own folder. Git shares the history between them, but build tools treat each folder as a different project:
target folder with every dependency compiled again. Five worktrees of a project with a 4 GB target can mean 20 GB.node_modules. npm and Yarn copy every package into each one. pnpm links files from its shared store instead, so extra worktrees cost far less with pnpm.~/Library/Developer/Xcode/DerivedData, with its own build products and index.Removing a worktree's folder takes its target and node_modules with it. DerivedData in Xcode's default location and extra simulators stay behind, so they keep piling up after the agents are done.
Inside any checkout of the repository, list its worktrees and the size of each:
git worktree list
git worktree list --porcelain | sed -n 's/^worktree //p' | while IFS= read -r wt; do du -sh "$wt"; done
If your worktrees live inside the main checkout, as with .claude/worktrees/, the main checkout's total includes them.
To see which project each DerivedData folder belongs to, with its size:
for d in ~/Library/Developer/Xcode/DerivedData/*/; do
printf '%s\t%s\n' "$(du -sh "$d" | cut -f1)" "$(plutil -extract WorkspacePath raw "$d/info.plist" 2>/dev/null)"
done | sort -hr
Each folder's info.plist records the path of the project it was built from, so several entries for the same project at different worktree paths are the duplicates.
Simulators and their runtimes:
du -sh ~/Library/Developer/CoreSimulator
xcrun simctl list devices
xcrun simctl runtime list
Open Xcode › Settings › Locations and set Derived Data to Relative. Xcode then puts build output in a DerivedData folder next to the project or workspace, inside the worktree, instead of in ~/Library. When the worktree goes, its build output goes with it.
This setting applies to every project you open in Xcode, not just one. Two things to do with it:
DerivedData/ to your .gitignore. Otherwise it shows up as untracked files, and git worktree remove refuses to remove the worktree.xcodebuild -derivedDataPath DerivedData …Folders already in the default location stay there. Delete the ones for worktrees you have removed, or see how to clear Xcode DerivedData.
Remove devices whose runtime is no longer installed. This only deletes devices that can't run anyway:
xcrun simctl delete unavailable
Remove a device an agent created and you no longer need, using its UDID from xcrun simctl list devices. This deletes the device and the apps and data on it:
xcrun simctl delete <UDID>
Runtimes are the largest part, several GB each. List them, then delete one you no longer test on by its identifier from the list:
xcrun simctl runtime list
xcrun simctl runtime delete <identifier>
Run xcrun simctl help runtime to see the options your Xcode version supports. You can also remove runtimes in Xcode › Settings › Components (Platforms in older versions of Xcode): click the information button next to a runtime and then Delete. Check the size of ~/Library/Developer/CoreSimulator afterwards, since a runtime can take a while to be removed.
Most of a debug build's size is debug info, and most of that is for dependencies you never step through. In the Cargo.toml at the root of your workspace:
[profile.dev.package."*"]
debug = false
"*" matches every dependency but none of your workspace's own packages, so your code keeps full debug info and backtraces still show your own file and line numbers. The cost is that you can't inspect variables inside dependency code in a debugger. Dependencies recompile once after the change, and every worktree's target is smaller from then on. Cargo only reads profiles from the workspace root, so a setting in a member crate's Cargo.toml is ignored.
sccache caches compiler output, so when a second worktree compiles the same dependency at the same version, it is copied from the cache instead of compiled again. Install it and turn it on for every Cargo build:
brew install sccache
Then in ~/.cargo/config.toml:
[build]
rustc-wrapper = "sccache"
Check that it is getting hits with sccache --show-stats.
This saves build time, not disk space. Each worktree still gets a full target folder, and the cache itself lives in ~/Library/Caches/Mozilla.sccache and grows up to 10 GB by default (set SCCACHE_CACHE_SIZE to change it). It also has limits:
~/.cargo/registry, which is the same for every worktree, so they hit. Your own crates sit at a different path in each worktree, so they compile again.dylib, cdylib and proc-macro crates.Pointing every worktree at one shared target folder with CARGO_TARGET_DIR would save disk, but Cargo locks the build directory while it builds, so parallel agents end up waiting on each other.
Remove finished worktrees with git rather than by deleting the folder:
git worktree remove <path>
This deletes the worktree folder, including gitignored build output inside it such as target, node_modules and a Relative DerivedData folder. Things to know:
--force removes it anyway and deletes those files.git worktree unlock <path> only once nothing is running there.git worktree prune to clear git's record of it.To keep a worktree but free its space, delete just its build output inside it with cargo clean and rm -rf node_modules. Both come back on the next build or install.
SymbolSweep finds Rust target folders, node_modules and Xcode DerivedData across your project folders, including the worktrees inside them, and lists each with its size and project. Scanning is free and never deletes anything. Build output you choose to delete is moved to the Trash, so you can put it back, and simulators are listed with instructions rather than deleted.
Deleting needs a one-time $12 license for one Mac. Requires macOS 13 or later on Apple silicon. See how it works.
Yes, if the build output is gitignored. git worktree remove deletes the whole worktree folder, including ignored folders such as target, node_modules and a Relative DerivedData folder. It refuses if there are untracked or modified files unless you pass --force. It doesn't touch DerivedData in Xcode's default location, simulators or the sccache cache.
It saves disk, but Cargo locks the build directory while it builds, so parallel agents end up waiting for each other. That defeats the point of running them in parallel.
No. It saves build time by reusing compiled dependencies across worktrees, but each worktree still gets its own target folder, and the cache itself uses up to 10 GB by default.
No. Simulator devices and runtimes are shared by every project on the Mac. They grow when agents create extra devices to test in parallel and when old runtimes pile up.