← Back to Technical Practice

CI/CD Practice

Building an iOS CI/CD Pipeline on Mac mini M4 Cloud Server

~5 min read

Building iOS CI/CD on Mac mini M4 Cloud Server - Kvmkit

Once a team grows, 'whose machine can produce a build' itself becomes the bottleneck. After we migrated our iOS project's CI/CD entirely toKvmkit's Mac mini M4 cloud server, build wait times dropped noticeably and signing incidents nearly vanished. This is our account of the pitfalls we hit building this pipeline from scratch and theFastfileand cache strategy we landed on — for teams also evaluating cloud Mac.

왜 CI/CD에 클라우드 Mac mini M4를 선택했나

Xcode builds are classic 'compute-intensive + strongly version-dependent' tasks, hard to maintain stably on a local Runner long-term. We chose cloud Mac nodes based on three factors:

  • Controlled specs: the image pins Xcode and CLT versions,preventingthe 'only he can compile because he manually upgraded his OS' problem.
  • Scale on demand: spin up extra nodes for regression testing before a release and release them when done — no need to keep hardware reserved year-round for peak loads.
  • 24/7 always-on: M4's idle power draw is low — nightly builds and scheduled security scans can run unattended without worrying about electricity costs or noise.

The first mistake we made: treating a 'cloud server' as just a remote display and only using it for manual builds. We only started getting the real value after connecting it to the CI trigger chain.


CI/CD pipeline design

Stage breakdown

For a complete release pipeline, we split it into four stages:

  1. Code pull & dependency resolution (SPM / CocoaPods)
  2. Unit tests & static analysis (parallel)
  3. xcodebuild archiveArchive & signing
  4. Upload to TestFlight and notify on-call channel

Hooks & trigger conditions

mainEvery merge to a branch automatically triggers stages 1–2. Only arelease/*tag triggers stages 3–4, avoiding consuming signing quota on every minor change. When debugging Fastlane scripts locally, we habitually useCtrl+Cto interrupt a full run and re-run only the failing step — saves a lot of wait time.

Example Fastfile snippet
lane :ci_archive do
  cocoapods
  run_tests(scheme: "Kvmkit")
  build_app(
    scheme: "Kvmkit",
    export_method: "app-store",
    output_directory: "./build"
  )
  upload_to_testflight(skip_waiting_for_build_processing: true)
end

The script itself isn't complicated. The key is making it produce consistent results when run repeatedly on thesame image baseline— which is why we write the image version number into build logs, making it easy to trace whether a failure was an environment issue or a code issue.


Cache & dependency management

Without proper caching, the time downloading dependencies eats the speed advantage of cloud builds. Below is the comparison table we derived after three months in production:

Cache itemWithout cacheWith image cache
CocoaPods install~4–6 minutes~30 seconds
SPM dependency resolution~3 minutes~15 seconds
DerivedData incremental buildClose to full build80%+ hit rate

A few terms defined:

DerivedData
Xcode's incremental build artifact cache. Reusing it across builds significantly reduces second-compile times.
SPM cache
Swift Package Manager's local cache of fetched package source and resolution results. Prevents re-downloading from remote repos on every build.
Image baseline
The system snapshot the cloud server boots with, containing pinned Xcode and CLT versions plus pre-warmed dependency caches.
Team viewing cache hit rate for cloud builds on a monitoring dashboard
Tracking cache hit rate as a dedicated panel is more useful for finding regressions than just looking at total build time

Common issue troubleshooting

The most overlooked point: an expired cert doesn't fail immediately — it fails at the very last step of uploading to TestFlight, by which point the entire pipeline has been spinning idle for 10+ minutes. We now put a cert expiry check in stage 1 — fail fast, alert fast.

Early on we used a"nightly full cache wipe and rebuild"approach to prevent cache rot. We later switched to cache invalidation by image version number (reuse if version unchanged, clear on image upgrade). This preserves speed while preventing stale caches from lurking silently for weeks.

"Don't trust one green CI run; trust ten consecutive green CI runs." — this is a line we repeat in our on-call runbook, especially during the first two weeks on a new cloud node.

FAQs

What are the security differences between a cloud Mac mini and a self-hosted Mac Runner?

The cloud node's system image is maintained by the provider as a baseline version. Teams still need to manage access to signing certs and Provisioning Profiles themselves. Recommend injecting certs only into runtime env vars, not persisting to the image, and clearing the keychain before returning the node.

Can free Xcode Cloud credits fully replace this whole setup?

For small teams, Xcode Cloud is completely sufficient. But when the need for parallel builds, custom scripts, or cross-project shared caches grows, a self-hosted pipeline on cloud Mac nodes is more flexible and easier to cap costs.

When multiple projects share the same pool of cloud nodes, how should certs be isolated?

Recommend using a separate keychain or keychain profile per project. The build script imports at start and clears at end, preventing different projects' certs from contaminating the same system-level keychain.

M4 Mac mini에서 CI/CD 실행 — 이게 진정한 편안함

All workflows in this article — Xcode, Fastlane, CocoaPods, SPM — are first-class citizens on macOS natively, requiring no VM or compatibility layer. The Mac mini M4's unified memory architecture prevents signing, archiving, and uploading (I/O-compute mixed tasks) from dragging each other down.~4Widle power draw also makes 24/7 on-call node electricity costs almost negligible.

Compared to a self-hosted Mac Runner, a cloud node eliminates worrying about data center cooling, system update windows, and hardware failure replacements — all that ops burden is offloaded, letting the team focus on improving pipeline quality.

If your team is also struggling with 'whose machine can compile',now is the perfect time to migrate CI to cloud Mac mini M4——View Kvmkit plan options— spin up your first build node in minutes.

Need technical support or advice on choosing a plan?

If you encounter issues using Mac instances or CI/CD pipelines, check the help center first. For ordering and pricing, see the pricing page.