Beta · Xcode 26 and later · GitHub Actions and macOS

A shared compilation cache for Xcode.

CI runners and your team’s Macs reuse what earlier builds compiled.

01 · Shared cache

Cache Xcode builds across CI and every Mac

  • One step in the workflow, one command on a Mac. xcodebuild stays as it is.
  • The default branch writes; pull requests and Macs read what it compiled.
  • If the cache is unreachable, Xcode compiles as usual. A build never fails because of Warmbuild.
Explore the setup
Terminal
$ curl -fsSL https://dev.warmbuild.dev/install.sh | sh
Downloading warmbuild 1.12.0…
Installed warmbuild 1.12.0 (sha256 9c41…e07a) to ~/.warmbuild/bin/warmbuild
Added ~/.warmbuild/bin to PATH in ~/.zshrc.
 
Signing in with GitHub (once):
Open https://github.com/login/device and enter the code 7F2C-9QKD
Signed in to acme. The token is in the macOS Keychain (read-only, until 12/13/2026).
Warmbuild is on (read-only).
 
$ warmbuild status
Warmbuild 1.12.0: on (read-only), pid 41873
Account: acme (token until 12/13/2026)
Projects: Shop (.)
Last build (3 min ago), all worktrees: hits 1862 (1794 from Warmbuild, 68 local), misses 41
ExampleInstalling on a Mac, then the first build’s numbers. Yours appear after your own build.

02 · Test selection

Run only the tests a change reaches

  • On a pull request, the Action follows the changed files to the test suites that can reach them.
  • Changes to the project, a package manifest or resources run everything.
  • The default branch still runs every test; the dashboard counts what selection missed.
Explore test selection
Pull request · 2 files changed
  • Sources/Cart/CartStore.swift
  • Sources/Cart/PriceFormatter.swift
xcodebuild test -scheme Shop -destination "$DEST"
xcodebuild test -scheme Shop -destination "$DEST" \
  -only-testing:ShopTests/CartStoreTests \
  -only-testing:ShopTests/PriceFormatterTests \
  -only-testing:ShopTests/CheckoutTotalsTests
ExampleThe arguments come from $WARMBUILD_ONLY_TESTING on CI, or warmbuild tests --changed on a Mac.

03 · Test results

Reuse test results that already passed

  • After build-for-testing, each test target is keyed by the products it loads, its settings, the Simulator runtime and Xcode.
  • A target whose key passed before is left out, and the job reports that run’s result.
  • When every target passed before, the Simulator boot and the test step are skipped too.
Explore the test cache
Job summary · test-cache

Test cache: 2 of 3 test targets reused.

Example test cache plan
Test targetResult
ShopTestsreused from run 11873402219 (commit 4be0c1a): 412 tests, 38 s
ShopUITestsreused from run 11873402219 (commit 4be0c1a): 26 tests, 214 s
SearchTestsruns (recorded if it passes)
ExampleA push that changed only the search module. Opt-in, with the test-cache step.

04 · CI report

See where CI minutes go

  • After each job, the Action reads Xcode’s logs and result bundles and splits the time by kind of work.
  • Findings name a fix, what it would save and what that estimate assumes.
  • The dashboard keeps the history per repository, so a regression shows up as a step.
Explore the CI report
Job summary · build-and-test

Where this job’s minutes went

Example: where one job's time went
Kind of workTimeShare
Compile1.9 min31%
Tests84 s23%
Waiting (Simulator, teardown)47 s13%
Asset catalogs31 s8%
Cache22 s6%
Other70 s19%
Job (from the Warmbuild step)6.1 min

Xcode compilation cache: 2914 hits, 136 misses.

Findings

• Tests wait 47 s for the Simulator after the build — fix it and save about 37 s per build. Boot the Simulator in the background before the build starts…

ExampleIllustrative numbers, not a measurement. Your own appear after your first job.

05 · Crashes

Read crashes, not logs

  • When the app or a test host crashes during the tests, the crash report is symbolicated on the runner.
  • The job summary shows the exception, the top frames with file and line, and the test that was running.
  • The dashboard groups crashes by signature, so a repeat reads as one crash, not five failures.
Explore crash reports
Job summary · Crashes

ShopTests/CartStoreTests/testRemovingLastItemClearsTotal failed: Shop (com.example.shop) crashed: EXC_BREAKPOINT (SIGTRAP) — Fatal error: Index out of range

Shop`CartStore.remove(at:) CartStore.swift:88
Shop`CartStore.removeLast() CartStore.swift:61
ShopTests`CartStoreTests.testRemovingLastItemClearsTotal() CartStoreTests.swift:47
XCTestCore`__invoking___
XCTestCore`-[XCTestCase invokeTest]

Same crash as run 11873166052 on main. Full symbolicated report

ExampleThe same section links to the full report on the dashboard.

06 · Security and privacy

What leaves the runner, and who can read it

Cache contents
Compiler outputs of your builds, addressed by their hash. Each account has its own keys; nothing is shared across accounts.
Reports
Build metadata only: target and task names, durations, counts and sizes. Never source code or logs.
Who writes
Pushes to the default branch, unless you change the write rules. Pull requests and Macs only read.
Sign-in
CI uses the job’s short-lived GitHub OIDC token: no secret to paste. Macs sign in with GitHub; the token stays in the Keychain.
Integrity
Every object is checked against its hash when it is read. A mismatch is a miss, and Xcode compiles that file itself.
When it fails
If the cache is slow, unreachable or switched off, builds run as they did before.

Free during the beta.

Accounts are approved by hand. Pricing will be published here before it applies to anyone.

Sign in with GitHub