Why Relocation Instead of Deletion?

Deleting Xcode caches is effective but comes with tradeoffs. Every time you delete DerivedData, your next build is a full rebuild. Delete simulator runtimes and you face an 8-18GB download to get them back. Delete device support files and Xcode must re-prepare your device the next time you connect it.

Relocation gives you the best of both worlds: your internal SSD gets its space back, but the data remains accessible on an external drive. Xcode continues to work normally because macOS symlinks make the external location transparent. When Xcode looks for ~/Library/Developer/Xcode/DerivedData/, the symlink transparently redirects to the external SSD, and Xcode never knows the difference.

This approach is particularly valuable for:

  • 256GB MacBook owners who need to conserve every gigabyte of internal storage
  • Developers who work on many projects and want to keep build caches warm across all of them
  • Teams that need multiple simulator runtimes installed simultaneously for testing
  • Anyone who regularly hits the "Your disk is almost full" warning

Hardware Requirements

Not all external storage is suitable for Xcode data. Build performance depends heavily on random read/write speed, so you need fast storage.

Recommended: Thunderbolt / USB4 NVMe SSD

Specification Minimum Recommended
Interface USB 3.2 Gen 2 (10 Gbps) Thunderbolt 3/4 or USB4 (40 Gbps)
Drive Type NVMe SSD NVMe SSD
Sequential Read 1,000 MB/s 2,500+ MB/s
Sequential Write 800 MB/s 2,000+ MB/s
Capacity 256 GB 500 GB - 1 TB
File System APFS APFS (case-sensitive optional)

Not Recommended

  • USB 2.0 drives — Far too slow (480 Mbps). Builds will take 5-10x longer.
  • Traditional spinning hard drives (HDD) — Random read/write performance is 50-100x slower than NVMe. Xcode will feel unusable.
  • SD cards or USB flash drives — Low random I/O performance, limited write endurance, and frequent controller stalls make these unsuitable for build artifacts.
  • Network-attached storage (NAS) — Latency is too high for the constant small-file I/O that Xcode build systems produce.

Format requirement: The external drive must be formatted as APFS. Xcode and its tools rely on APFS features (cloning, snapshots). Do not use HFS+, exFAT, or NTFS. To format a drive as APFS, open Disk Utility, select the drive, click Erase, and choose "APFS" as the format.

What to Relocate

Not every Xcode directory is a good candidate for relocation. Here is a prioritized list:

Directory Typical Size Relocation Benefit Performance Impact
DerivedData/ 10-50 GB High Moderate (affects build speed)
Archives/ 5-20 GB High Low (accessed infrequently)
iOS DeviceSupport/ 10-30 GB High Low (read-only after initial cache)
CoreSimulator/Devices/ 5-15 GB Medium Moderate (affects simulator boot)
org.swift.swiftpm/ 1-5 GB Low Low

Archives and Device Support are the easiest wins — they are large, accessed infrequently, and have almost no performance impact when on an external drive. DerivedData has the largest space savings but the most noticeable performance impact since Xcode reads from it constantly during builds.

Step-by-Step: Relocating DerivedData

DerivedData is the most impactful directory to relocate. Here is the full process.

1 Quit Xcode

Make sure Xcode is completely closed. Check Activity Monitor if you are unsure. Also close any running simulators.

# Force quit Xcode and simulators (if needed)
killall Xcode 2>/dev/null
killall Simulator 2>/dev/null

2 Create the Destination on Your External Drive

Assuming your external SSD is mounted at /Volumes/ExternalSSD:

# Create a folder structure on the external drive
mkdir -p /Volumes/ExternalSSD/Xcode/DerivedData

3 Move the Existing Data

# Move the existing DerivedData to the external drive
# Using rsync for reliable transfer with progress
rsync -avh --progress ~/Library/Developer/Xcode/DerivedData/ /Volumes/ExternalSSD/Xcode/DerivedData/

For a 30GB DerivedData folder on a Thunderbolt SSD, this takes about 30-60 seconds. On USB 3.2, expect 2-3 minutes.

4 Verify the Transfer

# Compare sizes to make sure everything was copied
du -sh ~/Library/Developer/Xcode/DerivedData/
du -sh /Volumes/ExternalSSD/Xcode/DerivedData/

# Optionally compare file counts
find ~/Library/Developer/Xcode/DerivedData/ -type f | wc -l
find /Volumes/ExternalSSD/Xcode/DerivedData/ -type f | wc -l

5 Remove the Original and Create the Symlink

# Remove the original DerivedData folder
rm -rf ~/Library/Developer/Xcode/DerivedData

# Create a symbolic link from the original location to the external drive
ln -s /Volumes/ExternalSSD/Xcode/DerivedData ~/Library/Developer/Xcode/DerivedData

# Verify the symlink
ls -la ~/Library/Developer/Xcode/ | grep DerivedData
# Should show: DerivedData -> /Volumes/ExternalSSD/Xcode/DerivedData

6 Test It

Open Xcode, open a project, and build. Xcode should work exactly as before. Check that build products are being created on the external drive:

# Verify data is being written to the external drive
ls /Volumes/ExternalSSD/Xcode/DerivedData/

That is it. Xcode now transparently reads and writes DerivedData from your external SSD. Your internal drive has its space back.

Step-by-Step: Relocating Archives

The process is identical. Archives are accessed only when you use the Organizer or export an archive, so there is virtually no performance impact.

# Quit Xcode first, then:
mkdir -p /Volumes/ExternalSSD/Xcode/Archives
rsync -avh --progress ~/Library/Developer/Xcode/Archives/ /Volumes/ExternalSSD/Xcode/Archives/
rm -rf ~/Library/Developer/Xcode/Archives
ln -s /Volumes/ExternalSSD/Xcode/Archives ~/Library/Developer/Xcode/Archives

Step-by-Step: Relocating iOS DeviceSupport

# Quit Xcode first, then:
mkdir -p /Volumes/ExternalSSD/Xcode/iOS\ DeviceSupport
rsync -avh --progress ~/Library/Developer/Xcode/iOS\ DeviceSupport/ /Volumes/ExternalSSD/Xcode/iOS\ DeviceSupport/
rm -rf ~/Library/Developer/Xcode/iOS\ DeviceSupport
ln -s /Volumes/ExternalSSD/Xcode/iOS\ DeviceSupport ~/Library/Developer/Xcode/iOS\ DeviceSupport

What Happens When the Drive Is Disconnected?

This is the most important question to understand before relocating. When you unplug the external SSD:

  • The symlinks become "broken." They still exist, but they point to a path (/Volumes/ExternalSSD/...) that is no longer mounted. Xcode sees an empty or missing directory.
  • Xcode will not crash. It handles missing DerivedData gracefully — it simply creates a new DerivedData folder at the symlink target (which will fail since the volume is not mounted) or reports that it cannot build until the issue is resolved.
  • Build attempts will fail. You will see errors like "unable to create directory" or "build directory does not exist." This is expected.
  • Reconnecting the drive fixes everything instantly. macOS re-mounts the volume, the symlinks start working again, and Xcode picks up where it left off. No data loss, no re-indexing required.

Important: Never eject the external drive while Xcode is building. This can corrupt the build cache or, in rare cases, leave the project in a state that requires a clean build. Always quit Xcode before disconnecting the drive.

Making Disconnection Safer

If you frequently disconnect your external drive (for example, when taking your MacBook to a meeting), consider these strategies:

  • Only relocate Archives and DeviceSupport — these are rarely accessed and their absence does not prevent builds. Keep DerivedData on the internal drive.
  • Create a fallback script that detects a missing volume and temporarily recreates the local directories:
#!/bin/bash
# xcode-check-drive.sh — run this before opening Xcode
EXTERNAL="/Volumes/ExternalSSD"

if [ ! -d "$EXTERNAL" ]; then
  echo "External drive not connected."
  echo "Creating temporary local directories..."

  # Remove broken symlinks and create local dirs
  for dir in DerivedData Archives "iOS DeviceSupport"; do
    target="$HOME/Library/Developer/Xcode/$dir"
    if [ -L "$target" ] && [ ! -d "$target" ]; then
      rm "$target"
      mkdir -p "$target"
      echo "  Created local: $dir"
    fi
  done

  echo "Xcode will work normally but data is on internal drive."
  echo "Reconnect the external drive and run this script again to restore symlinks."
else
  echo "External drive connected. Checking symlinks..."

  for dir in DerivedData Archives "iOS DeviceSupport"; do
    target="$HOME/Library/Developer/Xcode/$dir"
    external_dir="$EXTERNAL/Xcode/$dir"

    if [ -d "$target" ] && [ ! -L "$target" ]; then
      echo "  Restoring symlink for: $dir"
      # Merge any locally created data back
      rsync -avh "$target/" "$external_dir/" 2>/dev/null
      rm -rf "$target"
      ln -s "$external_dir" "$target"
    fi
  done

  echo "All symlinks verified."
fi

Performance Benchmarks

The key question: how much slower is building from an external drive? The answer depends heavily on your hardware. Here are real-world benchmarks from a mid-size Swift project (approximately 200 source files, 15 SPM dependencies) on a 2023 MacBook Pro M3:

Storage Clean Build Incremental Build Index Time
Internal Apple SSD 42 seconds 3.1 seconds 18 seconds
Thunderbolt 4 NVMe (Samsung T7 Shield) 48 seconds (+14%) 3.4 seconds (+10%) 21 seconds (+17%)
USB 3.2 Gen 2 NVMe (SanDisk Extreme) 55 seconds (+31%) 4.2 seconds (+35%) 26 seconds (+44%)
USB 3.0 SATA SSD 78 seconds (+86%) 6.8 seconds (+119%) 41 seconds (+128%)

The takeaways:

  • Thunderbolt NVMe SSDs add about 10-15% to build times. For most developers, this is imperceptible in day-to-day work.
  • USB 3.2 NVMe SSDs add 30-45%. Noticeable on large projects but still very usable.
  • SATA SSDs over USB 3.0 add 80-130%. This starts to feel sluggish, especially for incremental builds where you expect near-instant feedback.
  • Incremental builds matter more than clean builds. You do clean builds rarely but incremental builds dozens of times per day. A Thunderbolt NVMe SSD adds just 0.3 seconds to each incremental build — completely negligible.

Troubleshooting Common Issues

Xcode says "Build directory does not exist"

The external drive is not mounted. Reconnect it, or remove the broken symlink and create a local directory as a fallback.

Permission errors after symlinking

Make sure the external drive has the correct permissions. APFS drives formatted on your Mac should inherit your user permissions. If you see permission errors:

# Fix permissions on the external Xcode folder
chmod -R u+rwX /Volumes/ExternalSSD/Xcode/

Symlink disappeared after macOS update

Rare, but some macOS updates can reset ~/Library/Developer/Xcode/ directory structure. Re-create the symlink using the same command from Step 5.

Drive mount point changed

If macOS mounts the drive as /Volumes/ExternalSSD 1 instead of /Volumes/ExternalSSD (this happens when the original mount point has a stale reference), the symlinks will break. Fix by ejecting, waiting a moment, and reconnecting. To prevent this, always properly eject the drive before disconnecting.

Slow builds after relocation

Verify your drive's actual throughput:

# Quick disk speed test
dd if=/dev/zero of=/Volumes/ExternalSSD/speedtest bs=1m count=1024 2>&1 | tail -1
rm /Volumes/ExternalSSD/speedtest

If you are seeing write speeds under 500 MB/s, the drive may be connected to a slower port or the cable may not support full USB 3.2/Thunderbolt speeds. Check your cable and port.

How to Roll Back

If you decide to move everything back to the internal drive, the process is straightforward:

# Quit Xcode first
killall Xcode 2>/dev/null

# For each relocated directory:
# 1. Remove the symlink
rm ~/Library/Developer/Xcode/DerivedData

# 2. Copy data back from external drive
cp -R /Volumes/ExternalSSD/Xcode/DerivedData ~/Library/Developer/Xcode/DerivedData

# Or, if you don't need the cached data, just create an empty directory
mkdir ~/Library/Developer/Xcode/DerivedData

That is all it takes. Remove symlink, copy back (or start fresh), and everything is back to the default setup.