Xcode Image Coverage on macOS GitHub Actions Runners
WarpBuild macOS runners ship three macOS images across five labels. See the Xcode versions and simulator runtimes on each image, prices, and how to pin one.
Last verified:
The Xcode versions a GitHub Actions job can use are decided by the macOS image the runner boots, so choosing an Xcode version means choosing a runner label. WarpBuild macOS runners ship three macOS images, macOS 14, macOS 15, and macOS 26, across five warp- labels, and the two macOS 26 labels carry Xcode 27.0 (build 27A5194q) on top of the Xcode versions in the upstream GitHub image.
This page lists every macOS label with its image, size, and per-minute rate, maps each image to the Xcode versions and simulator runtimes it carries, prices a real iOS pipeline against GitHub-hosted macOS list prices, and shows the workflow syntax for pinning an image and selecting a toolchain inside the job.
Catalog
WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners. The macOS runners are Apple Silicon on ARM64, with multiple sizes and configurations per chip: a 6 vCPU shape and a 12 vCPU shape on the two current images.
| Label | macOS image | vCPU | Memory | Storage | Price per minute |
|---|---|---|---|---|---|
warp-macos-26-arm64-6x | macOS 26 | 6 | 22 GB | 120GB SSD | $0.08 |
warp-macos-26-arm64-12x | macOS 26 | 12 | 44 GB | 270GB SSD | $0.16 |
warp-macos-15-arm64-6x | macOS 15 | 6 | 22 GB | 120GB SSD | $0.08 |
warp-macos-15-arm64-12x | macOS 15 | 12 | 44 GB | 270GB SSD | $0.16 |
warp-macos-14-arm64-6x | macOS 14 | 6 | 22 GB | 120GB SSD | $0.08 |
Two aliases exist on top of those labels. warp-macos-latest-arm64-6x resolves to warp-macos-15-arm64-6x and warp-macos-latest-arm64-12x resolves to warp-macos-15-arm64-12x, because the latest tag tracks GitHub's macos-latest tag, which currently points at macOS 15. A job that names an alias moves to a different image the day the alias moves, which is the main reason Xcode-sensitive builds pin the versioned label instead.
The 12 vCPU shape carries 270GB of storage against 120GB on the 6 vCPU shape. That gap matters on Xcode work more than the vCPU count does for some teams, because a downloaded simulator runtime, a derived data directory, and an archive for distribution can each run into tens of gigabytes. Runner storage is ephemeral and is deleted when the runner terminates, so nothing accumulates between jobs.
macOS 13 runners were removed on June 8, 2026. Workflows still naming a macOS 13 label queue without a match, so move them to macOS 14, macOS 15, or macOS 26.
Xcode and simulator coverage by image
Every WarpBuild macOS image is built from the corresponding upstream GitHub runner image and carries the same tooling, so the Xcode set on each image is the published upstream set. The macOS 26 image is the one with an addition on top.
| macOS image | Labels | Xcode versions on the image | Simulator runtimes | Published list |
|---|---|---|---|---|
| macOS 26 | warp-macos-26-arm64-6x, warp-macos-26-arm64-12x | The Xcode versions in the upstream GitHub macOS 26 arm64 image, plus Xcode 27.0 (build 27A5194q) added by WarpBuild | iOS 27.0 (24A5355p), tvOS 27.0 (24J5289o), watchOS 27.0 (24R5289n), visionOS 27.0 (24M5291p) with Xcode 27.0, plus the runtimes in the upstream image | macos-26-arm64 readme and the WarpBuild macOS 26 tooling section |
| macOS 15 | warp-macos-15-arm64-6x, warp-macos-15-arm64-12x (aliases warp-macos-latest-arm64-6x, warp-macos-latest-arm64-12x) | The Xcode versions in the upstream GitHub macOS 15 arm64 image | The simulator runtimes bundled with those Xcode versions in the upstream image | macos-15-arm64 readme |
| macOS 14 | warp-macos-14-arm64-6x | The Xcode 15 line, with 15.4 as the default, matching GitHub-hosted macOS 14 | The simulator runtimes bundled with the Xcode 15 line in the upstream image | macos-14-arm64 readme |
The readme files linked in that table are the authoritative per-build inventory. GitHub regenerates them on every image release, so an exact patch version such as 16.2 or 16.4 belongs in the readme rather than in a marketing page that refreshes on a 90 day cadence. The preinstalled software docs keep the readme link for each WarpBuild image in one place.
macOS 14 is the narrowest image of the three by design. GitHub removed Xcode 14 and Xcode 16 from its macOS 14 images on November 4, 2024, leaving the Xcode 15 line, and WarpBuild followed the same removal. The default on that image was corrected to 15.4 on March 31, 2025 so that a job which never calls xcode-select compiles with the same toolchain it would get on a GitHub-hosted macOS 14 runner. Teams that need Xcode 16 or later on an older base OS have to move up an image rather than reach for a version that image no longer carries.
The macOS 26 tooling addition
The warp-macos-26-arm64-6x and warp-macos-26-arm64-12x runners ship Xcode 27.0, build 27A5194q, in addition to the Xcode versions present in the upstream GitHub macOS 26 image. Four simulator runtimes come with it: iOS 27.0 (24A5355p), tvOS 27.0 (24J5289o), watchOS 27.0 (24R5289n), and visionOS 27.0 (24M5291p). A job on either label can build against the 27.0 SDKs and run tests on the 27.0 simulators without a download step in the workflow.
That addition carries a support window worth writing into your workflow comments during review. Xcode 27.0 on macOS 26 is a WarpBuild addition on top of the upstream GitHub image, and it is maintained only until the official macOS 27 images are released. When those images ship, the Xcode 27.0 bundle path on the macOS 26 image stops being the place to pin, and jobs that hardcode it need one edit. Runner image changes are published in the WarpBuild changelog, which is the surface to watch for that switch.
The practical value of the addition is timing. Simulator runtimes for a new OS version are usually the blocker for a team that wants to test against a beta or a fresh release, because downloading a runtime inside a job adds minutes to every run and burns disk on a 120GB image. Having the runtime resident on the image turns that into a destination string.
What the coverage adds up to
Counting the catalog: three macOS images, five labels, two sizes on each of the two current images, and one Xcode version on macOS 26 that the upstream GitHub image does not carry. Those counts are measured on the same base images the GitHub-hosted runners use, rather than on a synthetic benchmark. Everything else on the image matches the GitHub-hosted equivalent, which is what makes a label swap a one-line change.
Two limits belong in the same paragraph as the coverage. macOS runners do not support nested virtualization and cannot run Docker, so a container step in an iOS pipeline has to move to a Linux job. The WarpBuild cache is enabled by default on Linux runners, so a macOS job caches with actions/cache against GitHub's cache service in the usual way.
Pricing
macOS rates are flat per minute by size and do not change with the image. A macOS 26 job and a macOS 14 job at the same vCPU count cost the same.
| Configuration | Label or GitHub shape | vCPU | Memory | Price per minute | Per hour | 30-minute build |
|---|---|---|---|---|---|---|
| WarpBuild 6 vCPU | warp-macos-26-arm64-6x, warp-macos-15-arm64-6x, warp-macos-14-arm64-6x | 6 | 22 GB | $0.080 | $4.80 | $2.40 |
| WarpBuild 12 vCPU | warp-macos-26-arm64-12x, warp-macos-15-arm64-12x | 12 | 44 GB | $0.160 | $9.60 | $4.80 |
| GitHub-hosted larger Apple Silicon | macos-latest-xlarge (macos_xl) | 5 | 14 GB | $0.102 | $6.12 | $3.06 |
| GitHub-hosted standard Apple Silicon | macos-latest (actions_macos) | 3 | 7 GB | $0.062 | $3.72 | $1.86 |
| GitHub-hosted larger Intel | macos-latest-large (macos_l) | 12 | 30 GB | $0.077 | $4.62 | $2.31 |
WarpBuild rates come from the cloud runner catalog and the pricing page. GitHub list prices come from GitHub's published Actions minute multipliers, checked on 2026-08-13.
The matched Apple Silicon pair is the first and third rows: the closest GitHub-hosted shape to a 6 vCPU WarpBuild macOS runner is macos-latest-xlarge. At $0.080 against $0.102, that is $0.022 lower per minute, 22 percent lower, or $1.32 lower per hour of macOS build time. Read the last two rows before quoting that number internally. GitHub's 3 vCPU standard macOS runner at $0.062 per minute is the cheapest macOS minute on either price list, and the 12 vCPU Intel shape is a different architecture from an Apple Silicon build host, so it is not a matched comparison for a job that expects arm64 Xcode.
Pricing is purely usage based. There is no base subscription fee, no platform fee, and no seat fee. Billing is per minute of runner time, so the cost of an Xcode job is its wall clock duration times the rate in the table above.
Worked model: one iOS pipeline
Take a team with 40 pull request builds per weekday. Each build runs a 14-minute compile and simulator test job on the 6 vCPU shape, and a nightly release build runs 26 minutes on the 12 vCPU shape every day of the month.
Pull request minutes: 40 builds times 14 minutes is 560 minutes per weekday. Over 22 weekdays that is 12,320 minutes per month.
- On
warp-macos-26-arm64-6xat $0.080 per minute: 12,320 times 0.080 is $985.60 per month. - On GitHub's
macos-latest-xlargeat $0.102 per minute: 12,320 times 0.102 is $1,256.64 per month. - Difference on the pull request leg: $271.04 per month.
Nightly release minutes: 26 minutes times 30 days is 780 minutes on warp-macos-26-arm64-12x at $0.160 per minute, which is $124.80 per month. GitHub's list has no 12 vCPU Apple Silicon shape to match that row, so the honest comparison stops at the pull request leg.
Total macOS spend in this model on WarpBuild: $985.60 plus $124.80 is $1,110.40 per month, with $10 of that covered on a new account because signup includes $10 free credits.
Worked model: an Xcode version matrix
Compatibility matrices are where Xcode image coverage turns into a line on the invoice. Add a second matrix leg so every pull request builds against Xcode 27.0 on macOS 26 and against the default toolchain on macOS 15. The per-build cost doubles, because both legs are full 14-minute jobs on the 6 vCPU shape.
- One leg: 12,320 minutes per month at $0.080 is $985.60.
- Two legs: 24,640 minutes per month at $0.080 is $1,971.20.
- The same two-leg matrix on GitHub's
macos-latest-xlargeat $0.102: 24,640 times 0.102 is $2,513.28, a difference of $542.08 per month.
The lever that usually beats both numbers is scope. Run the second leg on the merge queue and on nightly runs rather than on every pull request, and the added minutes drop by roughly the ratio of merges to pull request pushes. The macOS runner cost guide works through the same arithmetic for a full macOS fleet, and the pricing page carries the complete rate card including cache and storage line items.
Run as many jobs as your workflows need. Generally available Linux and Windows runners do not have plan-level concurrency caps. For high concurrency specifically on macOS, contact [email protected] so capacity is staged ahead of a large matrix rollout.
Configuration
Two edits move an Xcode job onto a WarpBuild macOS runner: the runs-on label and, when the Xcode version matters, an explicit toolchain selection.
Pin an image label and select Xcode
name: ios-pr
on:
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: warp-macos-26-arm64-6x
env:
DEVELOPER_DIR: /Applications/Xcode_27.0.app/Contents/Developer
SIMULATOR_NAME: iPhone 16 Pro
steps:
- uses: actions/checkout@v4
- name: Record the toolchain in the job log
run: |
xcodebuild -version
xcrun simctl list runtimes
- name: Build and test
run: |
xcodebuild test \
-scheme AppScheme \
-destination "platform=iOS Simulator,name=$SIMULATOR_NAME,OS=27.0" \
-resultBundlePath TestResults.xcresult
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: TestResults.xcresultDEVELOPER_DIR is the lightest way to select a toolchain: it is scoped to the job, needs no sudo, and applies to xcodebuild, swift, and every xcrun invocation in the steps that follow. The alternative is sudo xcode-select -s /Applications/Xcode_27.0.app/Contents/Developer as its own step, which changes the machine-wide default for the rest of the job.
The bundle names under /Applications are set by the image. Run ls -1 /Applications | grep Xcode once on the label you plan to use, or read the bundle list in the upstream image readme linked in the catalog table above, then pin the exact name. The xcodebuild -version and xcrun simctl list runtimes steps in the workflow above are cheap insurance: they put the toolchain and the available runtimes in the job log, so an image update that changes either shows up as a diff in the log rather than as a confusing compile error weeks later.
Pin the label rather than the latest alias
jobs:
compatibility:
strategy:
fail-fast: false
matrix:
include:
- runner: warp-macos-26-arm64-6x
xcode_app: Xcode_27.0.app
- runner: warp-macos-15-arm64-6x
xcode_app: Xcode.app
runs-on: ${{ matrix.runner }}
env:
DEVELOPER_DIR: /Applications/${{ matrix.xcode_app }}/Contents/Developer
steps:
- uses: actions/checkout@v4
- run: xcodebuild -version
- run: xcodebuild build-for-testing -scheme AppScheme -destination "generic/platform=iOS Simulator"Both legs name a versioned label. Neither uses warp-macos-latest-arm64-6x, and that is deliberate: the alias tracks GitHub's macos-latest tag, so the image under it moves when GitHub moves, and a job that depends on a specific Xcode version would move with it. Xcode.app is the image default on macOS 15, which is the right pin for a leg whose job is to catch breakage against whatever the current default toolchain is.
A useful split for a mixed pipeline is to keep the pull request job on one pinned label, run the matrix on the merge queue, and give the release job the 12 vCPU label so the archive and notarization step gets the larger disk. Sizes and rates for both shapes are in the cloud runner docs, and the per-image tooling links live in the preinstalled software docs.
Two behaviors to plan around
macOS runners do not support nested virtualization and cannot run Docker. A pipeline that lints with a containerized tool or builds a server image alongside the app should keep that work in a Linux job on a warp-ubuntu-latest-x64-4x runner at $0.008 per minute and pass artifacts between jobs, which is cheaper than paying macOS rates for a step that does not need macOS.
Runner storage is ephemeral. A 120GB disk on the 6 vCPU shape is ample for a checkout, derived data, and one archive, and it fills faster when a job downloads an extra simulator runtime on top of the resident ones. Jobs that need several runtimes at once belong on the 12 vCPU shape with 270GB.
Start on the macOS runner hub for the full macOS lineup, or go straight to the workload pages for iOS builds on GitHub Actions and Swift builds on GitHub Actions. Signup includes $10 free credits, which covers a few hundred minutes of macOS build time before any card is involved.
FAQ
Which Xcode versions are available on WarpBuild macOS runners?
Each macOS image carries the Xcode versions of the upstream GitHub image it is built from, and the macOS 26 labels warp-macos-26-arm64-6x and warp-macos-26-arm64-12x additionally ship Xcode 27.0 (build 27A5194q) with the iOS 27.0, tvOS 27.0, watchOS 27.0, and visionOS 27.0 simulator runtimes. macOS 14 carries the Xcode 15 line with 15.4 as the default.
How do I select a specific Xcode version inside a workflow?
Set DEVELOPER_DIR to the Contents/Developer path of the Xcode bundle you want, or run sudo xcode-select -s on that path before the build step. Print xcodebuild -version in the same job so the log records which toolchain compiled the artifact.
Does warp-macos-latest-arm64-6x always give me the newest Xcode?
No. The latest alias resolves to the macOS 15 image, in sync with GitHub's macos-latest tag, so a job on that alias gets the macOS 15 Xcode set. Pin warp-macos-26-arm64-6x when you need the macOS 26 image and Xcode 27.0.
How long does Xcode 27.0 stay on the macOS 26 image?
Xcode 27.0 is a WarpBuild addition on top of the upstream GitHub macOS 26 image and is maintained only until the official macOS 27 images are released. Track the runner image changelog and re-pin your DEVELOPER_DIR path when that switch happens.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.