iOS Simulator Runtimes on macOS GitHub Actions Runners
See which iOS, tvOS, watchOS, and visionOS simulator runtimes each WarpBuild macOS image carries, per-minute prices, and how to assert a runtime in a job.
Last verified:
A GitHub Actions job can only boot a simulator whose runtime is already installed on the runner image, so the runtimes available to xcodebuild test are decided by the macOS label in runs-on. WarpBuild macOS runners carry the simulator runtimes bundled with the Xcode versions in each image, and the two macOS 26 labels additionally carry the iOS 27.0, tvOS 27.0, watchOS 27.0, and visionOS 27.0 runtimes that ship with Xcode 27.0.
This page lists the runtime coverage of each macOS image, gives the per-minute rate for every macOS label, prices the minutes a job spends downloading a missing runtime, and shows the assertion step that turns a missing runtime into a fast, readable failure instead of a confusing xcodebuild error.
Catalog
WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners. The macOS runners are Apple Silicon on ARM64, in a 6 vCPU shape and a 12 vCPU shape across five warp- labels.
| Label | macOS image | vCPU | Memory | Storage | Price per minute |
|---|---|---|---|---|---|
warp-macos-26-arm64-6x | macOS 26 | 6 | 22 GB | 120GB SSD | $0.080 |
warp-macos-26-arm64-12x | macOS 26 | 12 | 44 GB | 270GB SSD | $0.160 |
warp-macos-15-arm64-6x | macOS 15 | 6 | 22 GB | 120GB SSD | $0.080 |
warp-macos-15-arm64-12x | macOS 15 | 12 | 44 GB | 270GB SSD | $0.160 |
warp-macos-14-arm64-6x | macOS 14 | 6 | 22 GB | 120GB SSD | $0.080 |
Runtime coverage by image
Every WarpBuild macOS image is built from the corresponding upstream GitHub runner image and carries the same tooling, so the resident runtimes on an image are the ones bundled with that image's Xcode versions. The macOS 26 image is the one with an addition on top.
| macOS image | Labels | iOS | tvOS | watchOS | visionOS | Per-build inventory |
|---|---|---|---|---|---|---|
| macOS 26 | warp-macos-26-arm64-6x, warp-macos-26-arm64-12x | 27.0 (24A5355p) plus the runtimes in the upstream image | 27.0 (24J5289o) plus the runtimes in the upstream image | 27.0 (24R5289n) plus the runtimes in the upstream image | 27.0 (24M5291p) plus the runtimes in the upstream image | macos-26-arm64 readme and the macOS 26 tooling table |
| macOS 15 | warp-macos-15-arm64-6x, warp-macos-15-arm64-12x (aliases warp-macos-latest-arm64-6x, warp-macos-latest-arm64-12x) | Bundled with the image Xcode set | Bundled with the image Xcode set | Bundled with the image Xcode set | Bundled with the image Xcode set where that Xcode carries a visionOS runtime | macos-15-arm64 readme |
| macOS 14 | warp-macos-14-arm64-6x | Bundled with the Xcode 15 line, 15.4 default | Bundled with the Xcode 15 line | Bundled with the Xcode 15 line | Bundled with the Xcode 15 line where that Xcode carries a visionOS runtime | 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 runtime build string for the macOS 14 and macOS 15 images belongs in the readme rather than in a page that refreshes on a 90 day cadence. The preinstalled software docs keep the readme link for each WarpBuild image in one place, and the cloud runner docs carry the label, size, and rate for every macOS shape.
The macOS 26 image ships the Xcode 27.0 SDKs and simulator runtimes while GitHub's upstream macOS 27 runner image is in beta, and a dedicated macOS 27 image follows once that image is released. Xcode 27.0 on macOS 26 is maintained until then, so a workflow that pins a /Applications/Xcode_27.0.app path needs one edit when the switch happens.
Two aliases sit on top of the versioned 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, in sync with GitHub's macos-latest tag. A job that needs the 27.0 runtimes names the macOS 26 label directly, because the alias moves when the upstream tag moves.
Three constraints shape how much runtime coverage a job can lean on. macOS 13 runners were removed on June 8, 2026, so workflows still naming a macOS 13 label queue without a match. macOS runners do not support nested virtualization and cannot run Docker, so container steps in an iOS pipeline belong in a Linux job. Runner storage is ephemeral and is deleted when the runner terminates, so a downloaded runtime never survives to the next job: the download repeats on every run that needs it.
Pricing
macOS rates are flat per minute by size and do not change with the image or with the number of runtimes on it. A job on macOS 26 and a job on macOS 14 at the same vCPU count cost the same.
| Configuration | Label or GitHub shape | vCPU | Memory | Price per minute | 30-minute job |
|---|---|---|---|---|---|
| WarpBuild 6 vCPU | warp-macos-26-arm64-6x, warp-macos-15-arm64-6x, warp-macos-14-arm64-6x | 6 | 22 GB | $0.080 | $2.40 |
| WarpBuild 12 vCPU | warp-macos-26-arm64-12x, warp-macos-15-arm64-12x | 12 | 44 GB | $0.160 | $4.80 |
| GitHub-hosted largest macOS ARM64 | macos_xl | 5 | 14 GB | $0.102 | $3.06 |
warp-macos-latest-arm64-6x (6 vCPU, 22 GB) costs $0.08 per minute against $0.102 per minute for the largest GitHub-hosted macOS ARM64 runner (5 vCPU, 14 GB): 22 percent lower list price. GitHub list price checked on 2026-08-13, from GitHub's published Actions minute multipliers. WarpBuild rates come from the pricing page.
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, which is what makes a runtime download a line on the invoice rather than a free convenience.
What a runtime download costs at job time
Time the download and install step in your own job log first, then read across. Each row is a step duration you supply, and the arithmetic is that duration times the macOS rate.
| Download and install step | Cost per job at $0.080 | 200 jobs per month | 800 jobs per month |
|---|---|---|---|
| 3 minutes | $0.24 | $48.00 | $192.00 |
| 6 minutes | $0.48 | $96.00 | $384.00 |
| 10 minutes | $0.80 | $160.00 | $640.00 |
On the 12 vCPU shape at $0.160 per minute, every figure in that table doubles: a 6-minute step is $0.96 per job and $192.00 across 200 jobs. A simulator runtime is a multi-gigabyte download, so the step also competes for the 120GB disk on the 6 vCPU shape. Matrices that need several runtimes in one job belong on the 12 vCPU shape with 270GB.
The cheapest version of this line is not having it. Pinning a label whose image already carries the runtime you test against drops the download step, and the job pays for compile and test minutes only. Signup includes $10 free credits, which covers a few hundred minutes of macOS runner time while you measure the two shapes against your own test suite.
Configuration
Two edits put a simulator job on a WarpBuild macOS runner with a runtime guarantee: the runs-on label, and an assertion step that fails early when the runtime is absent.
Assert the runtime before the test step
name: ios-simulator-tests
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: warp-macos-26-arm64-6x
env:
DEVELOPER_DIR: /Applications/Xcode_27.0.app/Contents/Developer
RUNTIME_ID: com.apple.CoreSimulator.SimRuntime.iOS-27-0
SIMULATOR_NAME: iPhone 16 Pro
steps:
- uses: actions/checkout@v4
- name: Record the toolchain and runtimes in the job log
run: |
xcodebuild -version
xcrun simctl list runtimes
- name: Assert the iOS 27.0 runtime is installed
run: |
if ! xcrun simctl list runtimes --json | grep -q "$RUNTIME_ID"; then
echo "::error::$RUNTIME_ID is not on this image"
exit 1
fi
- name: 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.xcresultMatching on the runtime identifier rather than the display name is what makes the assertion reliable: com.apple.CoreSimulator.SimRuntime.iOS-27-0 is stable across builds of the same runtime, while the display string carries a build suffix that changes. The xcrun simctl list runtimes step above it costs a second and puts the whole inventory in the log, so an image update that adds or removes a runtime reads as a diff between two runs instead of a test failure someone has to bisect. Device names are a separate axis: confirm SIMULATOR_NAME against xcrun simctl list devicetypes on the label you pin.
Download a runtime only when it is missing
- name: Ensure the iOS runtime is present
run: |
if ! xcrun simctl list runtimes --json | grep -q "$RUNTIME_ID"; then
echo "Runtime missing on this image, downloading"
time xcodebuild -downloadPlatform iOS
fiThe guard matters more than the download. Wrapping the download in the same identifier check means the step is a no-op on images that already carry the runtime, and the time prefix writes the duration into the log, which is the number to put in the cost table above. Running xcodebuild -downloadAllPlatforms instead pulls every platform and multiplies both the minutes and the disk use.
DEVELOPER_DIR selects the toolchain for xcodebuild, swift, and every xcrun call in the steps that follow, without sudo and without changing the machine-wide default. Pin it to the bundle that carries the runtime you assert on, so the OS= value in the destination string and the SDK the tests compile against stay in sync.
Start from the macOS runner hub for the full lineup, read what simulator runtimes ship on macOS runners for the short version of this page, and see the iOS simulator test guide for the surrounding pipeline. Term definitions live in the simulator runtime glossary entry.
FAQ
Which simulator runtimes ship on WarpBuild macOS runners?
Each macOS image carries the simulator runtimes bundled with the Xcode versions in the upstream GitHub image it is built from. The two macOS 26 labels, warp-macos-26-arm64-6x and warp-macos-26-arm64-12x, additionally carry iOS 27.0 (24A5355p), tvOS 27.0 (24J5289o), watchOS 27.0 (24R5289n), and visionOS 27.0 (24M5291p), which ship with Xcode 27.0 (build 27A5194q).
How do I check that a runtime exists before the test step runs?
Run xcrun simctl list runtimes as an early step and fail the job when the runtime you need is missing. Matching on the runtime identifier, such as com.apple.CoreSimulator.SimRuntime.iOS-27-0, is more precise than matching on the display name, and the full listing in the log makes an image change readable as a diff.
What does downloading a simulator runtime inside a job cost?
Runner time at the macOS rate. On the 6 vCPU shape at $0.080 per minute, a 6-minute download and install step adds $0.48 per job, which is $96.00 across 200 jobs in a month. Pinning a label whose image already carries the runtime removes the step and its cost.
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.