Can GitHub Actions Build iOS Apps Without a Mac?
No. An iOS archive needs Xcode, and Xcode runs only on macOS, so the job lands on a macOS runner such as warp-macos-latest-arm64-6x at $0.08 a minute.
Last verified:
No. An iOS archive is produced by Xcode, Apple publishes Xcode for macOS only (Xcode minimum requirements), and no supported cross-platform path produces a signed .ipa, so the job that builds one has to land on a macOS runner.
Answer
What you can skip is owning the hardware: a macOS runner is rented per minute by the workflow, starting at $0.08 per minute for warp-macos-latest-arm64-6x (WarpBuild cloud runners, checked on 2026-08-13). Three of Apple's tools decide the platform of the job. xcodebuild drives the build and the archive, xcrun simctl boots the simulator runtimes, and codesign plus notarytool handle signing. All four ship inside Xcode and the macOS command line tools, and Apple does not distribute the iOS SDKs for any other operating system. The open source Swift toolchain does run on Linux (swift.org install), which is why Swift server code compiles there, and that toolchain carries the standard library and Foundation rather than UIKit, SwiftUI, or the iOS SDKs.
GitHub Actions answers this with macOS runners, and the runner is where the cost of an iOS pipeline concentrates. WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners, and the macOS fleet registers against your organization as five labels:
| Runner label | OS | vCPU | Memory | Storage | Per minute |
|---|---|---|---|---|---|
warp-macos-26-arm64-6x | macOS 26 | 6 | 22GB | 120GB SSD | $0.08 |
warp-macos-26-arm64-12x | macOS 26 | 12 | 44GB | 270GB SSD | $0.16 |
warp-macos-15-arm64-6x | macOS 15 | 6 | 22GB | 120GB SSD | $0.08 |
warp-macos-15-arm64-12x | macOS 15 | 12 | 44GB | 270GB SSD | $0.16 |
warp-macos-14-arm64-6x | macOS 14 | 6 | 22GB | 120GB SSD | $0.08 |
Every row comes from the cloud runners documentation, checked on 2026-08-13. The macOS 15 labels also answer to the aliases warp-macos-latest-arm64-6x and warp-macos-latest-arm64-12x, so latest tracks macOS 15 today. Pin an explicit version when a release branch must stay on one image. Per-minute rates for every label are on the pricing page.
Detail
What moves to Linux and what stays on macOS
A useful iOS workflow is a Linux job feeding a macOS job. Sorting the steps by which binary they call gives a clean split:
| Pipeline step | Runner | Why it lands there |
|---|---|---|
| Workflow, YAML, and shell linting | Linux | Needs a shell and a linter binary |
| Swift package dependency resolution | Linux | Manifest evaluation and Git fetches under the Linux Swift toolchain |
| Ruby and Bundler install for tooling gems | Linux | Package installation, no Xcode call |
| Backend or API contract tests for the app's services | Linux | Server code, already cross-platform |
| Changelog, release notes, and screenshot metadata generation | Linux | Text and asset processing |
| App Store Connect metadata and TestFlight group changes | Linux | REST over HTTPS (App Store Connect API) |
| Unit and UI tests on a simulator | macOS | xcrun simctl and the simulator runtimes |
xcodebuild archive and -exportArchive | macOS | Xcode and the iOS SDK |
| Code signing and notarization | macOS | codesign and notarytool |
| Binary upload to App Store Connect | macOS | The upload tool ships with Xcode, and the .ipa is produced there |
One more constraint pushes work leftward: macOS runners do not support nested virtualization and cannot run Docker (cloud runners documentation). Any container step in an iOS pipeline, including a service container for integration tests or a Dockerized backend used by UI tests, belongs on a Linux runner regardless of cost.
A split pipeline
name: ios
on:
pull_request:
jobs:
checks:
runs-on: warp-ubuntu-latest-x64-4x
steps:
- uses: actions/checkout@v4
- name: Lint workflows and project configuration
run: |
yamllint .github/workflows
./scripts/check-plist-keys.sh
- name: Resolve Swift package dependencies
run: swift package resolve
- name: Generate release notes
run: ./scripts/release-notes.sh > release-notes.md
- uses: actions/upload-artifact@v4
with:
name: release-notes
path: release-notes.md
archive:
needs: checks
runs-on: warp-macos-26-arm64-12x
env:
SIMULATOR_NAME: ${{ vars.SIMULATOR_NAME }}
steps:
- uses: actions/checkout@v4
- name: Select the Xcode version
run: |
sudo xcode-select -s /Applications/Xcode_27.0.app
xcodebuild -version
- name: List available simulators
run: xcrun simctl list devices available
- name: Test on a simulator
run: |
xcodebuild test \
-scheme AppScheme \
-destination "platform=iOS Simulator,OS=27.0,name=$SIMULATOR_NAME"
- name: Archive and export
run: |
xcodebuild archive \
-scheme AppScheme \
-destination 'generic/platform=iOS' \
-archivePath build/App.xcarchive
xcodebuild -exportArchive \
-archivePath build/App.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/ipa
- uses: actions/upload-artifact@v4
with:
name: ipa
path: build/ipa/*.ipaneeds: checks keeps the macOS job from starting when a lint failure has already sunk the run, which is the point of the split: a broken workflow file costs $0.008 per minute to discover instead of $0.16.
The macOS image and Xcode
The warp-macos-26-arm64-6x and warp-macos-26-arm64-12x runners ship Xcode 27.0 (build 27A5194q) with the iOS, tvOS, watchOS, and visionOS 27.0 simulator runtimes, on top of the Xcode versions present in the upstream GitHub macOS 26 image, while GitHub's upstream macOS 27 runner image is in beta (cloud runners documentation). A dedicated macOS 27 image follows once that image is released. Preinstalled tooling on the macOS 14, 15, and 26 images matches the corresponding GitHub-hosted images, with the package lists linked from the preinstalled software documentation.
What the macOS minutes cost
warp-macos-latest-arm64-6x is 6 vCPU with 22GB at $0.08 per minute. GitHub lists the largest macOS ARM64 runner, 5 vCPU with 14GB, at $0.102 per minute (GitHub Actions minute multipliers and the GitHub pricing page, checked on 2026-08-13). That is about 22 percent lower list price on a machine carrying one more vCPU and 8GB more memory: $0.0133 per vCPU-minute against $0.0204.
Worked model. A repository runs 400 pull request workflows a month. Run everything on macOS and the pipeline takes 14 minutes. Split it and the macOS leg drops to 9 minutes with 5 minutes of linting, dependency resolution, and note generation moved to warp-ubuntu-latest-x64-4x at $0.008 per minute.
- All-macOS on
warp-macos-26-arm64-12x: 400 x 14 x $0.16 = $896.00 per month. - All-macOS on
warp-macos-latest-arm64-6x: 400 x 14 x $0.08 = $448.00 per month. - Split across both runners: 400 x 9 x $0.08 = $288.00 on macOS, plus 400 x 5 x $0.008 = $16.00 on Linux, for $304.00 per month.
- The same 5,600 macOS minutes at GitHub's $0.102 list price would be $571.20 (GitHub pricing, checked on 2026-08-13).
Model your own minute counts with the macOS runner cost guide.
Around the runner sits the rest of the product surface: snapshot runners, remote Docker builders, GitHub Actions observability, an MCP server, and the Action Debugger. The Docker builders matter here because the container half of an iOS pipeline has to live off macOS anyway.
Related Questions
Do I need to own a Mac to ship an iOS app from GitHub Actions?
No. You need a macOS machine for the archive step, and a macOS runner is that machine. Point the job at a label such as warp-macos-26-arm64-12x and the workflow rents the machine per minute, billed at $0.16 a minute for the 12 vCPU size. Every label and size is in the macOS runner catalog.
Can xcodebuild run on a Linux runner?
No. xcodebuild, xcrun simctl, codesign, and notarytool ship inside Xcode and the macOS command line tools, and Apple publishes Xcode for macOS only. A Linux job can run the parts of the pipeline that never touch those binaries.
Which iOS pipeline steps are worth moving off macOS?
The steps that only need Git, a shell, and a language runtime. Workflow and configuration linting, changelog and release-note generation, backend contract tests, and App Store Connect API metadata calls all run on a Linux runner at a lower per-minute rate. The iOS on GitHub Actions solution page walks through the full pipeline shape.
What do macOS runner minutes cost compared with GitHub-hosted macOS runners?
warp-macos-latest-arm64-6x is 6 vCPU with 22GB at $0.08 per minute against $0.102 per minute for GitHub's largest macOS ARM64 runner at 5 vCPU with 14GB (GitHub Actions pricing, checked on 2026-08-13): about 22 percent lower list price on a larger machine. Rates for both macOS sizes are on the pricing page.
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.