
Short recommendation: for two to four iOS developers, rent one Figment self-managed M-series Mac (from $95/month; exact chip, RAM and disk confirmed in the quote) and give each developer their own macOS account using the runbook below. Move up to the Managed Mac Team plan ($999/month: two M-series Macs, two CI runners, team setup, backups, monitoring, one hour of monthly support) when you would rather not operate accounts and CI yourself. Request either at /mac-hosting/start.
When you rent a Mac for a small iOS team, the fastest anti-pattern is handing everyone the same macOS login. Within a day, build caches collide, one developer's DerivedData fills the disk, and Xcode fights over the same provisioning profile directory. The fix is straightforward: one macOS account per developer, isolated DerivedData per home directory, and a simple disk-use audit. Here is the full runbook.
Xcode stores intermediate build products in ~/Library/Developer/Xcode/DerivedData. When two developers build the same scheme from the same macOS account simultaneously, Xcode's build record lock and index database conflict. The result is corrupted incremental builds, spurious "failed to generate header" errors, and races that vanish when you restart—only to return the moment two people queue a build at the same time.
Separate macOS accounts sidestep all of this. Each user's home directory (/Users/alice, /Users/bob) contains its own DerivedData hierarchy, its own Keychain, and its own SSH agent socket. No build state is shared unless you deliberately configure a shared volume. The setup takes about five minutes per developer. For the DerivedData defaults and custom location options referenced below, see Apple's Xcode help on Change the location of derived data.
Log in with an admin account and run this block for each team member. Check existing UniqueIDs first—IDs at or above 501 are standard for human accounts—with dscl . -list /Users UniqueID. Increment UID_NUM for each new user.
#!/usr/bin/env bash
# Run as admin on the remote Mac. Repeat per developer.
set -euo pipefail
NEW_USER=alice
REAL_NAME="Alice Developer"
UID_NUM=502 # must be unique; verify with: dscl . -list /Users UniqueID
sudo dscl . -create /Users/$NEW_USER
sudo dscl . -create /Users/$NEW_USER UserShell /bin/zsh
sudo dscl . -create /Users/$NEW_USER RealName "$REAL_NAME"
sudo dscl . -create /Users/$NEW_USER UniqueID $UID_NUM
sudo dscl . -create /Users/$NEW_USER PrimaryGroupID 20 # 20 = staff
sudo dscl . -create /Users/$NEW_USER NFSHomeDirectory /Users/$NEW_USER
TEMP_PW="$(openssl rand -hex 12)"
sudo dscl . -passwd /Users/$NEW_USER "$TEMP_PW"
sudo createhomedir -c -u "$NEW_USER" >/dev/null
# Hand the password over through your team secret manager, never chat/email.
printf 'Stored temp password for %s in secret manager? Rotate on first login.\n' "$NEW_USER"
The createhomedir call initialises the full home-directory skeleton—including ~/Library—that macOS and Xcode expect. Avoid printing the generated password to a shared terminal or log; paste it into your secret manager and share it from there. Each developer should change their password on first login with passwd.
Each developer generates an SSH keypair on their local laptop (ssh-keygen -t ed25519 -C alice@team) and sends you the public half. Add it to that user's authorized_keys on the remote Mac:
# Run as admin on the remote Mac
set -euo pipefail
NEW_USER=alice
PUBKEY="ssh-ed25519 AAAAC3Nza...== alice@laptop" # replace with the actual key
sudo install -d -m 700 -o "$NEW_USER" -g staff /Users/$NEW_USER/.ssh
printf '%s\n' "$PUBKEY" | sudo tee -a /Users/$NEW_USER/.ssh/authorized_keys >/dev/null
sudo chmod 600 /Users/$NEW_USER/.ssh/authorized_keys
sudo chown "$NEW_USER":staff /Users/$NEW_USER/.ssh/authorized_keys
Do not reuse the same keypair across accounts. If Alice and Bob both authenticate with one private key you lose the ability to tell who made which change, and revoking access means rekeying both accounts. Keep each authorized_keys file owned by its user at mode 600; sshd rejects keys with loose permissions. Once each developer logs in to their own account, GitHub's SSH agent forwarding guide covers the client-side setup so they can push to GitHub without copying private keys to the remote Mac.
Figment access note: the $29 virtual Intel macOS plan is reached through a browser console, not inbound SSH, so multi-user SSH onboarding is a fit for a physical M-series Mac. Confirm SSH exposure and any firewall rules in the configuration quote at /mac-hosting/start.
Once each developer has their own macOS account, Xcode's default DerivedData path (~/Library/Developer/Xcode/DerivedData) is already isolated—it lives inside each user's home directory and is never touched by another account.
If you want the path visible and easy to clean, set it explicitly. In Xcode open Settings > Locations, change Derived Data to Custom, and enter ~/Developer/DerivedData. The shorter path also makes xcodebuild invocations tidier. The example below is illustrative, not a benchmark; substitute your own project, scheme and destination and run it against your repo:
xcodebuild build \
-project YourApp.xcodeproj \
-scheme YourAppScheme \
-destination 'generic/platform=iOS' \
-derivedDataPath "$HOME/Developer/DerivedData/YourAppScheme"
Passing -derivedDataPath explicitly in CI scripts prevents any stale path inherited from a previous session on the same account.
A remote Mac with four active developers accumulates gigabytes of DerivedData, Archives, and simulator runtimes quickly. Run this audit weekly or attach it to launchd:
#!/usr/bin/env bash
# disk-audit.sh – run as admin on the remote Mac
set -euo pipefail
echo "=== DerivedData per user ==="
du -sh /Users/*/Library/Developer/Xcode/DerivedData 2>/dev/null || echo "(none)"
echo
echo "=== Archives per user ==="
du -sh /Users/*/Library/Developer/Xcode/Archives 2>/dev/null || echo "(none)"
echo
echo "=== iOS Simulator runtimes (shared) ==="
du -sh /Library/Developer/CoreSimulator/Profiles/Runtimes/ 2>/dev/null || echo "(none)"
echo
echo "=== Disk free ==="
df -h / | awk 'NR==2 {printf "Free: %s of %s (%s used)\n", $4, $2, $5}'
If a user's DerivedData exceeds 20 GB, ask them to run rm -rf ~/Library/Developer/Xcode/DerivedData and let Xcode rebuild. Archives are worth keeping until the matching App Store Connect build is processed, then safe to remove. macOS does not expose per-user disk quotas through a GUI; for strict enforcement on a shared volume you would enable BSD quotas via edquota and quotaon. Most small teams find the weekly audit script adequate.
| Step | Tool / Command | Who runs it |
|---|---|---|
| Create macOS account | dscl block above | Admin |
| Initialise home directory | createhomedir -c -u alice | Admin |
| Hand over temp password | Secret manager | Admin → Developer |
| Add developer's SSH public key | authorized_keys block | Admin |
| Developer clones repo | git clone git@github.com:… | Developer (own account) |
| Set custom DerivedData path | Xcode > Settings > Locations | Developer |
| Weekly disk audit | disk-audit.sh | Admin or launchd |
| Remove stale DerivedData | rm -rf ~/Library/Developer/Xcode/DerivedData | Developer |
For two to four iOS developers, two Figment options are practical starting points.
Self-managed M-series from $95/month per machine. You run macOS accounts, Xcode versions and any CI yourself using the runbook above. Exact chip, RAM and disk are confirmed in the configuration quote; physical plans collect requests until supply is confirmed, so ask about current availability. A two-developer team usually fits on one machine ($95/month). A four-developer team that wants concurrent archive builds often adds a second machine, taking hardware to $190/month.
Managed Mac Team at $999/month. Two M-series Macs, two CI runners, team setup, backups, monitoring, and one hour of monthly support. The jump from $190 to $999 buys the CI runners, monitoring, backups, and the hands-on hour each month; it is worth it when your lead would rather ship features than operate dscl, keychains and runners.
The $29 virtual Intel macOS VM (2 vCPU, 8 GiB RAM, 80 GiB disk; Intel toolchains such as supported Xcode 26 or earlier) is a reasonable per-developer sandbox for scripting, documentation and compatible Intel builds, but it is accessed through a browser console rather than SSH and is not the right primary machine for a shared team workflow.
Start at Figment Mac Hosting or go straight to request a plan.
Related: Git and Xcode Source Control on a Remote Mac · Upload dSYMs to App Store Connect from Remote Mac · GitHub Actions Self-Hosted Runner on Mac