Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Speed Up CI Builds with a RAM Disk on Mac

This experiment needs a macOS host with at least 32 GB RAM so you can carve out a 12 GB RAM disk and still leave headroom for Xcode and parallel compilers. Figment's $29 virtual Intel macOS plan ships with 8 GiB RAM, so it is not the right box for this particular test; it is useful for Intel-compatible toolchains (Xcode 26 or earlier per Apple's Apple silicon porting notes), not for RAM-disk builds. For this task, request an M-series Mac from $95/month, or Managed Build Mac at $249/month (one M-series Mac, CI setup, backups, monitoring, 30 minutes of monthly support). Start the request at /mac-hosting/start and confirm RAM and disk in the quote. See current plans on /mac-hosting.

Xcode's DerivedData directory is a write-intensive workload. During a clean build Xcode writes module caches, intermediate .o objects, .swiftmodule files, and index data in parallel across many compiler processes. On older Intel Macs with slower SSDs, moving DerivedData to a RAM disk can produce a double-digit-percent reduction in wall time; on modern Apple silicon with Apple's NVMe controller the gap is smaller and project-dependent. This guide gives you a script to measure the difference on your actual hardware and project before you commit to it.

Why SSD I/O Limits Some Xcode CI Runs

Xcode's compiler driver schedules many parallel jobs and each writes output to DerivedData independently. On SATA SSDs or older PCIe drives, those writes queue behind I/O-depth limits and wall-clock time is spent waiting rather than compiling. A RAM disk moves reads and writes to DRAM latency (nanoseconds) rather than flash (microseconds). The benefit is largest on:

  • Intel Macs with consumer-grade SATA or early PCIe SSDs
  • Clean builds that regenerate all DerivedData from scratch
  • Large projects whose DerivedData exceeds 5 GB

Incremental builds benefit less, because the bottleneck shifts from storage to compile and link time once most outputs already exist on disk.

How macOS RAM Disks Work

macOS has two built-in commands. hdiutil attach -nomount ram://<sectors> returns a block device backed by RAM; diskutil erasevolume then formats and mounts it. The unit is a 512-byte sector, so the conversion is:

sectors = megabytes × 2048

For a 12 GB (12,288 MB) RAM disk: 12,288 × 2048 = 25,165,824 sectors. Check: 25,165,824 × 512 = 12,884,901,888 bytes = 12 GiB.

DEVICE=$(hdiutil attach -nomount ram://25165824)
diskutil erasevolume HFS+ "XcodeDerivedData" "${DEVICE}"
# Volume mounted at /Volumes/XcodeDerivedData

For the xcodebuild flags used below, see the Xcode build settings reference for related DerivedData settings and the archived xcodebuild tech note (TN2339) for its canonical archive invocation pattern. Confirm the exact flag behaviour against man xcodebuild on the Xcode version installed on your runner.

Sizing the RAM Disk

Reserve at most roughly one-third of the runner's RAM for the disk. Measure your project's DerivedData size first:

# After one normal build on the default path:
du -sh ~/Library/Developer/Xcode/DerivedData/YourApp-*/

Then pick a size with headroom. A rough guide:

Project sizeTypical clean DerivedDataRecommended runner RAM
Small (< 50 Swift files)1–2 GB16 GB
Mid-size (50–200 files)3–6 GB32 GB
Large (200+ files, many deps)6–14 GB32–64 GB

If DerivedData grows past the RAM disk size mid-build, the build will fail when the volume fills. Size conservatively and watch the first few runs.

The mount-ramdisk.sh Script

This creates the RAM disk, runs xcodebuild with DerivedData redirected, and tears the disk down on exit whether the build succeeded or failed. Pass workspace, scheme, and output as environment variables; use your real scheme name, not a placeholder.

#!/usr/bin/env bash
# mount-ramdisk.sh — build with Xcode DerivedData on a RAM disk
# Usage:
#   WORKSPACE=ios/YourApp.xcworkspace \
#   SCHEME=YourApp \
#   OUTPUT_DIR=./build \
#   RAM_DISK_MB=12288 \
#   bash mount-ramdisk.sh
set -euo pipefail

RAM_DISK_MB="${RAM_DISK_MB:-12288}"
DISK_NAME="XcodeDerivedData"
SECTORS=$(( RAM_DISK_MB * 2048 ))

WORKSPACE="${WORKSPACE:?Set WORKSPACE to your .xcworkspace path}"
SCHEME="${SCHEME:?Set SCHEME to your Xcode scheme name}"
OUTPUT_DIR="${OUTPUT_DIR:-./build}"
mkdir -p "${OUTPUT_DIR}"

echo "==> Creating ${RAM_DISK_MB} MB RAM disk (${SECTORS} sectors)..."
DEVICE=$(hdiutil attach -nomount "ram://${SECTORS}")
diskutil erasevolume HFS+ "${DISK_NAME}" "${DEVICE}" >/dev/null
MOUNT_POINT="/Volumes/${DISK_NAME}"
echo "==> Mounted at ${MOUNT_POINT} on ${DEVICE}"

cleanup() {
  echo "==> Detaching RAM disk ${DEVICE}..."
  hdiutil detach "${DEVICE}" -quiet -force || true
}
trap cleanup EXIT

ARCHIVE_PATH="${OUTPUT_DIR}/${SCHEME}.xcarchive"
DERIVED_DATA="${MOUNT_POINT}/DerivedData"

echo "==> xcodebuild archive"
echo "    Workspace:    ${WORKSPACE}"
echo "    Scheme:       ${SCHEME}"
echo "    DerivedData:  ${DERIVED_DATA}"
echo "    Archive path: ${ARCHIVE_PATH}"

xcodebuild \
  -workspace "${WORKSPACE}" \
  -scheme "${SCHEME}" \
  -configuration Release \
  -derivedDataPath "${DERIVED_DATA}" \
  -archivePath "${ARCHIVE_PATH}" \
  archive

set -euo pipefail makes the script exit on the first failure rather than reporting a failed build as a fast run. trap cleanup EXIT runs hdiutil detach on normal exit, error, or signal, so a killed CI job does not leak the RAM device until reboot. -derivedDataPath is a command-line argument to xcodebuild; it is not something you put in an .xcconfig build setting file.

If you want prettier output, pipe through a formatter in a way that preserves the real exit status, for example set -o pipefail; xcodebuild ... | xcbeautify. Do not swallow the exit code of xcodebuild with a plain pipe.

Measuring the Speedup (Worked Worksheet)

Run the same archive twice from an identical starting state. Record wall-clock real time from time and write both rows into a tiny worksheet.

# Clean baseline each run
rm -rf ~/Library/Developer/Xcode/DerivedData

# Baseline: default SSD DerivedData
time xcodebuild \
  -workspace ios/YourApp.xcworkspace \
  -scheme YourApp \
  -configuration Release \
  -archivePath ./build/ssd-test.xcarchive \
  archive

# RAM disk: via the script
rm -rf ~/Library/Developer/Xcode/DerivedData
time WORKSPACE=ios/YourApp.xcworkspace \
     SCHEME=YourApp \
     OUTPUT_DIR=./build \
     RAM_DISK_MB=12288 \
     bash mount-ramdisk.sh

Example worksheet with made-up numbers for illustration — replace with your own:

RunDerivedData locationreal timeDelta vs SSD
SSD #1~/Library/Developer/Xcode/DerivedData287 s—
SSD #2same281 s—
RAM #1/Volumes/XcodeDerivedData/DerivedData243 s−38 s
RAM #2same239 s−45 s

If average SSD is 284 s and average RAM is 241 s, the saving is 284 − 241 = 43 s per build, or 43 ÷ 284 ≈ 15.1%. Run at least two of each, discard the first warm run if you want to isolate steady-state behaviour, and only draw conclusions when the delta is bigger than the run-to-run variance. For finer I/O detail, use sudo fs_usage -f diskio | grep DerivedData or the Disk I/O template in Instruments.

M-Series Unified Memory: When the RAM Disk Helps Less

Apple silicon Macs share a unified memory pool across CPU and GPU and ship with fast internal NVMe. The ratio between DRAM speed and SSD speed is much tighter than on a 2015-era Intel Mac with a SATA SSD, so the RAM-disk advantage shrinks and becomes project-specific. Run the worksheet above on your own project before baking a RAM disk into production CI. If the delta is small, spend the time on other levers instead: explicit module builds, splitting slow test targets, and caching dependencies between runs — covered in the sibling guide on multiple Xcode versions in CI.

When you request a Figment M-series Mac on /mac-hosting/start, state the RAM you need (at least 32 GB for a 12 GB RAM disk plus Xcode) and the DerivedData footprint from du -sh above, so the quoted configuration actually fits the workload.

Related guides: Multiple Xcode versions in CI · Upload dSYMs in CI for crash reporting · Remote Xcode setup on Windows


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms