Home / GitHub Actions Mac Runner
GitHub Actions Mac Runner
A self-hosted GitHub Actions Mac runner lets your workflows build on a Mac you control, with caches that persist and no hosted macOS minutes to pay for. Hatmac rents you the dedicated Apple silicon Mac to run it on.
How self-hosted runners work
The GitHub Actions runner is a small application that runs on your Mac and polls GitHub over outbound HTTPS for jobs. When a workflow asks for matching labels, GitHub hands the job to your runner, which checks out the code and runs the steps in its work folder. No inbound ports are needed.
You can register a runner to a single repository, to an organization (shared by several repositories through runner groups) or to an enterprise. Organization runners are usually the most practical for teams.
Mac mini M4
16GB · 256GB SSD
Everyday iOS builds, CI runners and remote macOS.
from $119/mo
- Monthly$149/mo
- 6 months$139/mo
- 12 months$119/mo
Mac mini M6
16GB · 256GB SSD
Newer chip for faster compiles and test runs.
from $129/mo
- Monthly$169/mo
- 6 months$159/mo
- 12 months$129/mo
Mac mini M6
Most popular24GB · 512GB SSD
More memory and storage for larger projects and caches.
from $179/mo
- Monthly$209/mo
- 6 months$199/mo
- 12 months$179/mo
Mac mini M5 Pro
24GB · 512GB SSD
Pro-class CPU and GPU for heavy builds and small models.
from $229/mo
- 6 months$249/mo
- 12 months$229/mo
Prices in USD per month for each machine's starting configuration. More memory, storage or several machines? Ask us.
Register the runner
- Order a Mac and connect to it over SSH once the access details appear under My Macs.
- Install Xcode and the tools your workflows need. Our Xcode build server guide covers multiple Xcode versions and caching.
- In GitHub, open the repository or organization, then go to Settings → Actions → Runners → New self-hosted runner. Choose macOS and the ARM64 architecture.
- Run the commands GitHub shows, logged in as a dedicated CI user. The registration token is short-lived, so use it straight away.
mkdir ~/actions-runner && cd ~/actions-runner
# paste the curl download and tar commands shown on the GitHub page (osx-arm64)
./config.sh --url https://github.com/your-org/your-repo \
--token YOUR_REGISTRATION_TOKEN \
--name hatmac-m6 --labels xcode,m6 --unattended
Full options are in GitHub's self-hosted runner documentation.
Run it as a service
run.sh works for testing, but it stops when your session ends. Install the runner as a launchd service with the bundled script:
./svc.sh install
./svc.sh start
./svc.sh status
On macOS, svc.sh installs a launch agent for the user that configured the runner, so that user's session needs to be running. Logs are written to ~/Library/Logs/actions.runner.*. To update or remove the runner, stop the service, run ./svc.sh uninstall, then ./config.sh remove --token ....
Labels and runs-on
Every self-hosted runner gets the default labels self-hosted, macOS and ARM64. Add your own for capabilities, such as the Xcode version or machine size, and target them in runs-on. A job only goes to a runner that has all the listed labels.
jobs:
build:
runs-on: [self-hosted, macOS, ARM64, xcode]
steps:
- uses: actions/checkout@v5
- run: xcodebuild -version
- run: xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17'
Keep labels about capabilities, not machine names, so you can add a second Mac later without editing every workflow. For several machines, see our Mac build farm page.
Ephemeral or persistent runners
| Persistent | Ephemeral | |
|---|---|---|
| Lifetime | Stays registered and takes job after job | Takes one job, then unregisters |
| Caches | Warm DerivedData, packages and tools | Lost unless kept outside the work folder |
| Isolation | Leftovers from earlier jobs remain | Cleaner, but the Mac itself is still reused |
| Best for | Private repos, trusted contributors | Stricter isolation, autoscaling scripts |
An ephemeral runner is registered with --ephemeral and usually re-registered by a wrapper script after each job:
./config.sh --url https://github.com/your-org --token YOUR_TOKEN --ephemeral --unattended
./run.sh
On a dedicated physical Mac, most teams choose persistent runners because warm caches are the main speed gain.
Security note for public repositories
GitHub recommends using self-hosted runners only with private repositories. On a public repository, anyone can open a pull request from a fork, and a workflow could run their code on your Mac. If you must use one with a public repository, require approval for workflows from outside contributors, never run fork pull requests on the runner, and keep secrets out of those jobs. In every case, run the service as a non-admin user and keep signing material in a separate keychain.
For the bigger picture across CI systems, read our macOS CI/CD runner overview, or the step-by-step post iOS CI/CD on a cloud Mac mini.
FAQ
Does a GitHub Actions Mac runner need inbound ports open?
No. The runner connects out to GitHub over HTTPS and waits for jobs. You only need SSH or remote desktop for your own administration.
Can one Mac run several GitHub Actions runners?
Yes. Configure each one in its own folder with its own name. Xcode builds are memory-hungry, so on 16GB keep to one runner and use 24GB or more for two.
Do self-hosted runners use my GitHub Actions minutes?
Self-hosted runners do not use hosted-runner minutes, but GitHub's billing rules for self-hosted runners have changed over time, so check GitHub's current pricing page. Hatmac charges a fixed monthly price for the Mac.
Which plan should I start with?
The Mac mini M6 with 24GB and 512GB is our most popular plan for CI. It fits two Xcode versions and a warm cache. See pricing.