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.
Cache Xcode builds across CI and every Mac
- One step in the workflow, one command on a Mac.
xcodebuildstays 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.
$ 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
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.
- 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
$WARMBUILD_ONLY_TESTING on CI, or warmbuild tests --changed on a Mac.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.
Test cache: 2 of 3 test targets reused.
| Test target | Result |
|---|---|
| ShopTests | reused from run 11873402219 (commit 4be0c1a): 412 tests, 38 s |
| ShopUITests | reused from run 11873402219 (commit 4be0c1a): 26 tests, 214 s |
| SearchTests | runs (recorded if it passes) |
test-cache step.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.
Where this job’s minutes went
| Kind of work | Time | Share |
|---|---|---|
| Compile | 1.9 min | 31% |
| Tests | 84 s | 23% |
| Waiting (Simulator, teardown) | 47 s | 13% |
| Asset catalogs | 31 s | 8% |
| Cache | 22 s | 6% |
| Other | 70 s | 19% |
| 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…
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.
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
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.