Somewhere near the top of the workflow file, one line reads runs-on: macos-latest. It is usually the first line anyone writes and the last one anyone revisits, and every job that inherits it is billed at the Apple rate, including the ones that only check out code, run a linter or upload an artifact.
An iOS build needs a Mac. Most of an iOS pipeline does not.
Only three stages are locked to Apple hardware
Compiling with Xcode is the obvious one: every row in the Xcode system requirements is a macOS version. Signing a build for distribution runs through the same toolchain, and so does anything that drives the iOS Simulator, which ships inside Xcode. Everything else is platform-neutral, and Docker-based steps point away from the Mac by rule: workflows that use Docker container actions or service containers must run on a Linux machine with Docker installed.
Don’t miss the best of The Mac Observer
Set us as a preferred source and our Apple reporting ranks higher in your Google Search results and Discover feed — one tap, no account changes.
| Stage | Needs macOS? | Where it runs |
|---|---|---|
| Xcode build, signing and simulator tests | Yes | Mac pool |
| Lint, backend and API integration tests, API mocks | No | Linux host |
| Docker container actions and service containers | No, Linux required | Linux host |
| Caches, artifacts, notifications and release notes | No | Linux host |
Licensing keeps the Mac side where it is. The macOS Tahoe 26 license permits up to two additional virtual instances on each Apple-branded computer you own or control, for software development and testing, so Mac capacity grows by adding Macs. The rest of the pipeline is free to live anywhere.
A macOS minute costs more than ten Linux ones
A Linux 2-core runner costs $0.006 a minute on GitHub’s hosted fleet, against $0.062 for a macOS 3-core or 4-core runner, a ratio of more than ten to one. Rates were checked in September 2026.
Assume a pipeline burning 10,000 minutes a month, with 30 percent of it genuinely requiring macOS. Three thousand macOS minutes come to $186 and seven thousand Linux minutes to $42. Better than four fifths of the $228 bill is bought by the three stages locked to Apple hardware, so the discipline that pays is keeping everything else off them.
The seven days a dependency cache survives
Hosted runners also forget. The default cache allowance is 10 GB per repository, and entries not accessed in over seven days are removed. An iOS project carrying DerivedData, Swift Package Manager and CocoaPods artifacts across several Xcode versions and branches spends that budget quickly, and each eviction is paid for twice: once in download minutes and once in a compile that starts cold.
A machine with its own disk holds that cache for as long as the disk does. The same goes for a mock API, which a hosted runner starts and tears down on every job and a persistent host simply leaves running.
Putting the rest of the pipeline on one machine
A workable shape is a small pool of Mac minis, GitHub’s hosted macOS runners or EC2 Mac hosts for Xcode builds, signing and simulator tests, with everything else on a single Linux host registered as a self-hosted runner. Actions usage is free for self-hosted runners, so the cost of those stages becomes the cost of the machine.
An OVHcloud dedicated server is one way to buy that machine at a flat monthly price. OVHcloud’s specification for its bare metal range says “all its hardware resources are allocated exclusively to you” and that “there’s no virtualisation layer consuming resources on a dedicated server, so you’re guaranteed full use of the physical resources”.
A rented machine buys capacity and persistence, not supervision. Self-hosted runners should almost never be used for public repositories, and even on private ones anyone who can open a pull request can reach the runner’s secrets. Isolate the host, patch it, scope its credentials and prefer just-in-time runners, which perform one job and are then removed.
Migrate in this order:
- First, checkout and lint, which prove the runner registration.
- Second, the backend test suite, usually the largest platform-neutral block of minutes.
- Third, the API mocks, which become services that stay up between jobs.
- Last, caches and the artifact store, because a mistake there fails the build on the expensive runner.
If the pipeline runs three times a day
Volume is what makes the split worth doing. A team of three shipping a couple of builds a day, against a backend somebody else operates, has a modest macOS bill, and a host is fixed work, paid whether the pipeline is busy or idle.
The diagnostic is last month’s Actions invoice. Walk the jobs behind its macOS line and ask of each one whether it would have run on Linux. Three will hold out: the Xcode compile, the signing step, the simulator run. The rest belong on a machine rented by the month.
You still need Macs. You just don’t need them doing Linux’s work.
Discussion