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
Order Mac mini M4

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
Order Mac mini M6

Mac mini M6

Most popular

24GB · 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
Order Mac mini M6

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
Order Mac mini M5 Pro

Prices in USD per month for each machine's starting configuration. More memory, storage or several machines? Ask us.

Register the runner

  1. Order a Mac and connect to it over SSH once the access details appear under My Macs.
  2. Install Xcode and the tools your workflows need. Our Xcode build server guide covers multiple Xcode versions and caching.
  3. In GitHub, open the repository or organization, then go to Settings → Actions → Runners → New self-hosted runner. Choose macOS and the ARM64 architecture.
  4. 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

PersistentEphemeral
LifetimeStays registered and takes job after jobTakes one job, then unregisters
CachesWarm DerivedData, packages and toolsLost unless kept outside the work folder
IsolationLeftovers from earlier jobs remainCleaner, but the Mac itself is still reused
Best forPrivate repos, trusted contributorsStricter 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.