A self-hosted macOS runner you control

Register a dedicated Mac mini as a GitHub Actions or GitLab runner and keep your caches warm between builds.

Why self-host a macOS runner

A self-hosted runner is a machine you register with your CI service so it picks up jobs from your pipelines. On a dedicated Mac mini M6, every job gets the full 12-core CPU and 16 GB of memory, and the price stays $112 a month however many minutes your builds take.

The bigger win is state. DerivedData, Swift Package Manager checkouts, CocoaPods and Homebrew caches stay on the SSD between runs, so incremental builds start warm. You also choose exactly which Xcode versions are installed and when to update them, so a toolchain change happens when you decide.

Registering with GitHub Actions

In your repository or organisation settings, open Actions > Runners and choose New self-hosted runner, then pick macOS and the ARM64 architecture. GitHub shows a short list of commands: connect to the Mac over SSH, download and unpack the runner, and run ./config.sh with your repository URL and the one-time token.

To keep the runner going after you disconnect and after a restart, install it as a service with ./svc.sh install and start it with ./svc.sh start; it then runs under launchd like any other macOS service. The runner registers with the labels self-hosted, macOS and ARM64, and you can add your own, such as ios-release, to target specific jobs.

Using it in a workflow

In a workflow file, set runs-on to the runner’s labels, for example [self-hosted, macOS, ARM64]. Steps run directly on the Mac, so xcodebuild, xcrun, fastlane and your Homebrew tools are available without setup actions. Pick the Xcode for a job with sudo xcode-select -s or the DEVELOPER_DIR environment variable.

A typical iOS job checks out the code, resolves packages, runs xcodebuild test against a simulator destination and, on the main branch, archives the app and uploads it to TestFlight. Because the Mac keeps its caches, the same job is noticeably faster on the second run than on the first.

GitLab CI and other systems

For GitLab, install the runner with brew install gitlab-runner, register it with gitlab-runner register using the shell executor, and start it with brew services start gitlab-runner. Jobs tagged for that runner then execute on the Mac with your user’s environment and tools.

The same Mac works as a Jenkins agent over SSH, with the Buildkite agent, or with scheduled launchd jobs for nightly builds. With full admin rights, any CI system that offers a macOS agent can run here, and you can register more than one if different projects use different services.

Signing in CI

Code signing needs certificates in a keychain the runner can unlock. A common setup is a dedicated keychain created with the security command, holding the distribution certificate imported from a .p12 file and unlocked at the start of each job with a password kept in your CI secrets.

fastlane match does this for you: it stores encrypted certificates and profiles in a private repository and installs them when a job needs them. For uploads, an App Store Connect API key lets fastlane send builds to TestFlight with no password or two-factor prompt in the middle of a pipeline.

Keeping the runner healthy

A few habits keep a build Mac fast. Clear old DerivedData and simulator runtimes you no longer use, since the 256 GB SSD holds caches and archives alike. Update Xcode on a schedule you control, testing the new version on a branch first. GitHub recommends self-hosted runners for private repositories, which is how most teams use a dedicated build Mac.

On the billing side, monthly renewals come with reminders 3 days and 1 day ahead and 24 hours to fix a failed payment with your Mac untouched and reachable, so a card problem never stops your pipelines without warning.

Questions

How many jobs can run at once?
Each runner registration takes one job at a time. For light jobs you can register a second runner on the same Mac; heavy Xcode builds run best one at a time.
Does the runner start again after a reboot?
Yes. Installed as a service with ./svc.sh install, it is started by launchd automatically.
Can I notarise macOS apps in CI?
Yes. Sign with your Developer ID certificate and submit with xcrun notarytool, using an App Store Connect API key stored in your CI secrets.
Which plan suits a CI runner?
The monthly plan at $112: the Mac stays on around the clock with your caches in place. Try your pipeline on the 7-day pass ($49) first if you like.

Before you pay

Payment is handled by Stripe.

They show us how the site is used, including recordings of your visit; what you type stays hidden (PostHog, Google Analytics). These tools use cookies and start only if you say yes. You can change your mind at any time from the bottom of the page. If you say no to statistics, we only count your visit, without cookies. Cookie policy