On a Friday afternoon, the teammate who handles our releases dropped a question in chat: "Our monthly Mac mini lease ends next Wednesday — what happens to the certificates, simulator data, and Homebrew cache on it?" Nobody could rattle off a complete list on the spot — that's the classic warning sign of a migration about to go sideways. Cloud Mac minis are convenient to work with, but a lot of state quietly accumulates in places you forget about until the day you actually have to walk away, only to find it scattered across a dozen directories.
Why lease-end migrations so often fail
Most people think "migrating off" just means copying the project folder back to their laptop. But what actually breaks a build afterward is usually hidden configuration: deployment keys issued under ~/.ssh, distribution certificates sitting in the Keychain, incremental build indexes under ~/Library/Developer/Xcode/DerivedData, and the assorted caches that tools silently write into your home directory. None of this is visible day to day — but once the machine is decommissioned, it's gone for good.
Migrating off isn't "backing up files" — it's "reproducing a machine that can start working immediately." The real test isn't whether every file got copied, it's whether a build on the new machine produces the exact same output as the old one.
Pre-migration inventory: what actually has to leave with you
Splitting what you need to carry over into two categories up front already cuts down on omissions.
Dev environment configuration
This covers shell config (.zshrc/.zprofile), SSH keys and known_hosts, global Git config and credentials, Xcode signing certificates and provisioning profiles, and any Keychain entries exported via the security command. These files are small individually but every one of them matters — pack them into a dedicated archive.
Project and dependency caches
This covers your code repositories (in theory these all live remotely, but double-check any unpushed local branches), local CocoaPods and SwiftPM caches, the list of Homebrew packages installed (exporting a Brewfile with brew bundle dump is far cheaper than copying the entire /opt/homebrew tree), and lockfiles like Podfile.lock and .xcode-version.
A three-layer backup strategy: rsync deltas + tar archives + snapshot downloads
Don't count on any single method to cover every scenario — combining three layers is what actually holds up.
| Layer | Tool | Use case | Drawback |
|---|---|---|---|
| Layer 1 | rsync incremental sync | Ongoing daily backups of project files and configs | Requires a writable target; not great for huge binaries |
| Layer 2 | tar archive | One-time packaging of small, sensitive data like Keychain items and certificates | Not friendly to incremental updates |
| Layer 3 | Platform snapshot download | Last-resort fallback if the first two layers fail | Large, throttled by egress bandwidth, slow |
Incremental sync with rsync
Initiate from your local machine and sync the key directories on the Mac mini to local storage or an object-storage mount:
rsync -avz --delete \
--exclude 'DerivedData' \
--exclude 'node_modules' \
dev@hk1.oncemini.com:~/projects/ \
~/backup/mac-mini-hk1/projects/
Excluding regeneratable directories like DerivedData and node_modules cuts sync time from tens of minutes down to a few. Start running this daily a full week before the lease ends, rather than syncing for the first time on the last day — people consistently underestimate how long the first full sync takes.
Packing immutable archives
For data that rarely changes but absolutely cannot be lost — certificates, keys — pack it separately and encrypt it:
tar czf keychain-backup.tar.gz \
~/Library/Keychains \
~/.ssh
gpg -c keychain-backup.tar.gz
Sync or download the encrypted archive afterward, so plaintext keys never sit on the wire unencrypted.
Platform snapshot download as a fallback
If the first two layers didn't finish due to network issues, downloading a full machine snapshot from the console can serve as a last safety net — but estimate the size ahead of time. A 512GB system disk over residential bandwidth can take hours to pull down, so build in buffer time instead of kicking this off a few hours before the lease expires.
Common pitfalls and a verification checklist
- Forgetting to export a Brewfile via
brew bundle dump— reinstalling packages from memory on the new machine, with version numbers that don't match. - Backing up only the project code, not the local environment variables in
.env— the new machine's build fails on missing config. - Running rsync as a regular user, missing read permissions on system-level certificate files, so the archive ends up incomplete with no error raised.
- Starting the snapshot download only hours before expiry and running out of time the moment bandwidth dips.
- Leaving keys and tokens active on the old machine after migrating — those credentials technically remain valid after the lease ends, which is a real security exposure. Revoke them during your final login.
Cold-start verification on the new machine
Moving everything over isn't the finish line — run a full verification pass on the new environment before calling it done:
brew bundle install --file=Brewfile
pod install --repo-update
xcodebuild -workspace App.xcworkspace \
-scheme App -configuration Release \
clean build
shasum -a 256 build/App.app/App
Compare the shasum output from the old and new builds — only a match confirms the migration is actually complete. This step gets skipped a lot, but it's the only objective proof that nothing was lost in the environment, and it's far more reliable than "looks like it runs."
Frequently asked questions
How long is data kept after the lease expires?
The standard retention window is 72 hours. Finish your backup at least 48 hours before expiry rather than racing the deadline, since network hiccups or disk issues can eat into that buffer.
Should I use rsync or the platform snapshot download?
Use rsync for incremental backups to local disk or object storage first — it's fast and resumable. Snapshot download is large and capped by egress bandwidth, so treat it as a last-resort fallback only.
How do I confirm the new machine's environment is complete?
Rebuild from the same Brewfile, Podfile.lock, and .xcode-version on the new host, run a full build, and diff the artifact hashes — matching hashes is the real pass criterion.
Need a dedicated Mac mini to run your build pipeline?
Order now