1–5 min delivery

Dedicated Mac mini M4

$21.5 / day · bare metal
Configure Cloud Mac
Web VNC, no install SSH key access Five regions

FIELD NOTE · CI/CD

GitHub Actions Mac Runner Fixed or Elastic? 2026 Plan

This guide helps mobile engineering and platform teams choose between fixed Mac Runners, ephemeral runners, and a hybrid pool. It compares workload patterns, signing constraints, repository isolation, Runner Scale Set Client responsibilities, and failure fallback paths.

A GitHub Actions Mac Runner scaling design should start with evidence, not developer headcount. As of September 5, 2026, the official Runner Scale Set Client repository still labels the project Public Preview, while documenting API integration for custom elastic runner solutions, including macOS-based designs: official Runner Scale Set Client status and scope.

This week’s recommendation: keep a fixed Mac baseline when daily demand is stable and toolchain startup is expensive; add ephemeral Mac capacity when release peaks, repository sharing, or isolation requirements create short-lived pressure. Most teams should test a hybrid design before replacing every permanent node.

This article is for:

  • Mobile engineering leads balancing release queues against idle Mac capacity.
  • DevOps and platform engineers designing registration, routing, isolation, and cleanup.
  • Security and release owners deciding whether signing assets can enter temporary infrastructure.

Start with the workload scenario, not the runner count

A fixed Mac Runner is usually the simpler choice when the work arrives from a small set of trusted repositories, daily queue variation is limited, and the machine benefits from retained Xcode components, simulators, dependencies, or build caches. That simplicity is operational, not absolute. A permanent host still needs restricted repository access, patching, maintenance windows, log retention, and a backup path for failed hardware.

Elastic scaling becomes more attractive when the queue is concentrated around release windows, when several repositories compete for the same Mac pool, or when each job should begin from a cleaner trust boundary. An ephemeral runner can reduce the time that a job’s workspace and credentials remain on a runner, but the runner lifecycle is not the same as the Mac host lifecycle.

GitHub’s self-hosted Runner documentation distinguishes runner registration and execution behavior from the infrastructure that hosts the runner. We therefore treat “the runner disappeared” and “the Mac was cleaned and made safe for reuse” as separate control points: GitHub’s self-hosted Runner reference.

The decision conditions

Use the following branch list before changing capacity:

  • If routine jobs have predictable queue behavior, use a fixed baseline. Otherwise, reserve burst capacity for the measured peak rather than permanently adding hosts.
  • If Xcode versions, simulators, or private dependencies are expensive to prepare, keep the corresponding trusted workload on fixed nodes. Otherwise, evaluate ephemeral runners.
  • If multiple repositories have different trust levels, split runner groups before sharing capacity. Otherwise, a larger shared pool can amplify contamination risk.
  • If signing depends on long-lived keychain state or private network access, keep signing on a tightly controlled fixed path. Otherwise, temporary signing nodes are possible only with repeatable credential injection and revocation.
  • If the scaling controller cannot prove host provisioning, task registration, cleanup, and external log retention, do not call the system production-ready. Fall back to the fixed baseline.

This is the core of GitHub Actions Mac Runner elastic scaling: the queue should trigger a controlled capacity decision, not an automatic assumption that every Mac can be treated like a disposable container.

Operational warning: a temporary runner registration does not prove that the underlying Mac has been wiped, rebooted, disconnected from private networks, or stripped of credentials. Those checks belong to the host lifecycle.

Stable daily builds favor a fixed Mac baseline

A fixed node earns its place when its benefits recur throughout the week. The strongest evidence is not the number of developers. It is the workflow history:

  • Queue wait time by workflow and branch.
  • Runner busy time compared with idle time.
  • Failure reasons, including unavailable labels, toolchain errors, signing errors, and host failures.
  • Time spent restoring Xcode, simulators, package caches, and private dependencies.
  • The percentage of jobs that require a specific macOS or Apple Silicon environment.

A permanent node can preserve a carefully tested Xcode image and reduce repeated bootstrap work. It also makes diagnosis more direct because the platform team knows which host handled the build. That advantage disappears if several repositories write to the same workspace, leave processes behind, or depend on undocumented machine state.

A fixed runner should therefore have an explicit maintenance window, an owner, a replacement procedure, and a backup route for critical release work. Repository access must be limited through runner groups rather than assumed from network placement. GitHub documents runner-group access controls here: GitHub Runner Group permissions.

The fixed option scores well for stable operations, but poorly when the organization wants strong job-level isolation without maintaining many separate machines.

Workload signal Fixed Mac Runner Elastic or ephemeral Mac Runner Recommended reading
Small, trusted repository set Strong fit Possible but adds control-plane work Keep the baseline
Repeated Xcode setup cost Strong fit Requires a reliable image or bootstrap path Prefer fixed capacity
Short release bursts May leave capacity idle Strong fit if hosts arrive in time Test burst delivery
Mixed repository trust Needs strict groups and labels Strong fit only with real host cleanup Isolate before scaling
Private network dependency Easier to maintain Requires repeatable network enrollment Keep sensitive work narrow
Signing credentials Easier to control persistently Requires injection and revocation Separate signing jobs

Release peaks need a burst test, not a permanent purchase

A release peak is not automatically a reason to expand the permanent fleet. First separate the daily baseline from the burst. A short queue caused by a predictable merge train may be cheaper and safer to absorb with pre-warmed temporary Macs, while an unpredictable queue may require a fixed reserve.

Three designs are common:

  1. Add permanent runners. This works when the peak is frequent, long, and operationally important. It fails when the nodes remain idle for most of the release cycle.
  2. Pre-warm temporary runners. This works when the release window is known and the Mac image, network access, dependencies, and runner registration can be prepared in advance.
  3. Scale from queue signals. This works when the control plane can observe queued work, request Mac capacity, register the runner, route the correct job, and recover from a failed host.

The correct choice depends on evidence from the actual workflow. Record which jobs create the peak, how long they wait, how long a Mac takes to become usable, and whether signing or private dependencies delay readiness. A scaling pool that becomes available after the release queue has already cleared is not elastic capacity in a useful sense.

This is also where Xcode CI differs from a generic build queue. Simulator preparation, package resolution, signing, and device-specific tests can have different startup and failure patterns. A single queue metric hides those differences.

For a team considering remote capacity, our remote Mac rental options should be evaluated against the release calendar and the workflow’s real bootstrap requirements, not against a theoretical maximum runner count.

Shared Mac capacity needs routing before expansion

A shared pool can lower idle capacity, but it also creates a larger blast radius. Before adding another Mac, define the routing model:

  • Separate repositories by trust level.
  • Separate signing and non-signing work.
  • Separate Xcode versions and incompatible toolchains.
  • Separate ordinary tests from jobs that access private package sources.
  • Use labels only for stable capabilities, not as a substitute for access control.

GitHub describes labels as a way to route jobs to matching self-hosted runners, while access permissions remain a separate concern: GitHub self-hosted Runner labels. A label such as macos-arm64-xcode-current can express capability. It should not, by itself, grant a repository access to signing material.

Long-lived runners may retain workspaces, derived data, package caches, shell history, temporary files, and credentials. These leftovers can be useful for performance and dangerous for isolation. Ephemeral registration narrows the runner lifecycle, but it does not automatically guarantee that the Mac host is reset. For that reason, the acceptance test should include a deliberately failed job, a job that writes temporary data, and a check that the next repository cannot read it.

The cleanest design is often separate pools rather than one universal pool: a fixed, restricted signing pool; a baseline build pool; and an elastic pool for ordinary compile and test work.

Signing and private network work should stay on a separate path

Signing changes the decision. A build that only compiles code can often be rebuilt on a fresh Mac. A release job may depend on certificates, provisioning profiles, keychains, private package registries, internal APIs, or VPN and network policy.

Fixed capacity is appropriate when those dependencies require careful, persistent maintenance and the release process is tightly controlled. The risk is that a compromised workflow or overly broad repository permission can reach a high-value runner. Elastic capacity is appropriate only when the complete state can be created and removed reproducibly.

We recommend splitting ordinary build and test jobs from signing and publishing jobs. The ordinary path can use broader elastic capacity. The signing path should use a restricted runner group, narrower repository access, short-lived credentials where possible, explicit audit logs, and a cleanup or quarantine decision after every job.

GitHub’s security guidance warns that self-hosted runners require special care because workflow code can execute on infrastructure controlled by the repository: GitHub’s secure use reference for self-hosted runners. That warning applies directly to Mac CI. A convenient shared runner can become an access bridge between unrelated repositories.

Runner Scale Set Client connects the control plane, not the Mac fleet

The Runner Scale Set Client is relevant when a platform team wants to build a custom elastic runner system. Its documented role is to communicate with the Runner Scale Set API and generate temporary runner configuration. It does not automatically provision a physical Mac, start a rented host, install the required Xcode version, clean the machine, or recover a failed host.

That distinction matters because teams sometimes transfer assumptions from Actions Runner Controller, or ARC, to real macOS hosts. ARC is described by GitHub in the context of Kubernetes-oriented runner orchestration: GitHub’s Actions Runner Controller concept documentation. A Mac host is not interchangeable with a Kubernetes Runner Pod. The provisioning, access, image, reboot, and destruction steps remain infrastructure responsibilities.

The minimum validation chain should be tested in this order:

  1. A queued workflow produces a scaling signal.
  2. The infrastructure supplies an approved Mac host.
  3. The host receives the intended macOS, Xcode, architecture, and network state.
  4. The runner registers with the correct group and labels.
  5. One allowed workflow is routed to that runner.
  6. The job ends and the runner unregisters.
  7. The host is cleaned, rebuilt, disconnected, or quarantined according to policy.
  8. Logs remain available outside the host.
  9. A failed startup and a failed cleanup produce an actionable alert.

Do not mark the system ready because a runner appears online. The acceptance condition is a complete lifecycle with a known failure result.

Control-plane question Fixed baseline Elastic pool
Who supplies the Mac? Platform operations Platform operations or rental workflow
Who installs the toolchain? Maintenance process Image, bootstrap, or pre-warm process
Who controls repository access? Runner groups and policy Runner groups, labels, and policy
What happens after a failed job? Diagnose and restore or replace Unregister, clean, quarantine, or destroy
Where do logs survive? External log system External log system is essential
What is the fallback? Secondary fixed node or manual route Fixed baseline must remain available

Failure handling decides whether hybrid wins

Elastic scaling adds failure modes that fixed capacity does not: the scaling API may be unavailable, the Mac may fail to boot, registration may time out, the runner may update incorrectly, or external logs may not receive the job result.

A hybrid design should define a maximum queue wait and a clear stop condition for scaling. If the controller cannot obtain a trusted Mac within that boundary, it should stop requesting more capacity and route critical work to the fixed baseline or pause the release for manual approval. If cleanup fails, the host should be quarantined rather than returned to the pool.

GitHub provides monitoring and troubleshooting guidance for self-hosted runners, including operational signals that platform teams should review: GitHub monitoring and troubleshooting guidance. We would add one requirement: retain workflow and lifecycle evidence outside the Mac, because a failed or compromised host cannot be the only source of truth.

A practical rollout is a controlled rehearsal. Select one ordinary build workflow and one release-like workflow. Run the ordinary path on the fixed baseline, send the burst path to temporary capacity, force one registration failure, and simulate one cleanup failure. The result should answer whether the team can identify the failure, preserve the release path, and prevent a contaminated Mac from returning to service.

The hybrid score is usually the most defensible starting point

We score the three strategies against the conditions that usually matter to an engineering organization:

  • Fixed only: best for stable, trusted workloads and persistent toolchains; weakest for short peaks and strong job-level isolation.
  • Elastic only: best for bursty, multi-repository workloads with reproducible bootstrap and cleanup; weakest when signing state, private networks, or infrastructure readiness are difficult.
  • Fixed baseline plus elastic burst pool: best when daily demand is predictable but releases create real peaks; requires the most careful routing and lifecycle observability.

The score is not a benchmark. It is a decision aid. A team should select the hybrid option only when it can keep the fixed baseline capable of handling critical publishing work during elastic control-plane failure. Otherwise, the extra architecture creates dependence without providing a reliable fallback.

Our GitHub Actions Mac Runner acceptance guide can support the next review, especially for toolchain and hardware assumptions. Before committing to a broader fleet change, document the baseline queue, the release peak, the signing boundary, and the cleanup evidence.

FAQ

Can a self-hosted Mac Runner scale automatically with GitHub Actions?

Yes, but only as part of a larger infrastructure workflow. The scaling client can participate in API coordination and temporary runner configuration. Your system still has to provide the Mac, establish its approved state, register the runner, route the job, collect logs, and clean or quarantine the host. Treat automatic scaling as a lifecycle design rather than a single GitHub Actions setting.

Should Xcode CI use fixed Mac Runners or temporary runners?

Fixed runners suit stable workloads with persistent Xcode state, trusted repositories, and private dependencies. Temporary runners suit release bursts, stronger isolation, and workloads that can bootstrap from a known image. A hybrid is normally easier to validate: retain enough fixed capacity for critical publishing, then use temporary Macs for ordinary burst builds and tests.

Does Runner Scale Set Client support macOS nodes?

The official project documents custom elastic runner solutions that can include macOS. Its scope is API integration and temporary runner configuration. It is not a Mac provisioning service, host cleanup system, or replacement for infrastructure orchestration. Because the project remains marked Public Preview as of September 5, 2026, version and behavior checks belong in the change review.

How can Mac Runner scaling prevent cross-repository contamination?

Use runner groups to limit which repositories can access each pool, then use labels to express capabilities such as architecture or Xcode version. Separate signing jobs from ordinary tests. After a temporary job, verify both runner deregistration and host cleanup. Preserve logs externally, revoke temporary access, and quarantine any host whose cleanup result cannot be proven.

Should a release peak use permanent Mac capacity or rented Macs?

Permanent capacity is easier when the peak is frequent or when signing and private network state require continuous care. Rented Macs can be a sensible burst option when the extra capacity is needed for a defined window and the workflow can reproduce its setup and cleanup. Compare the release calendar, host delivery path, queue tolerance, and credential process before choosing.

The current alternative—buying and maintaining enough Mac hardware for the largest release peak—can leave expensive capacity idle between releases, tie the team to a fixed refresh cycle, and still require separate work for isolation, monitoring, and recovery. A Linux cloud host cannot replace macOS-specific Xcode and signing tasks, while a fully elastic design can fail if Mac delivery and cleanup are not predictable.

For teams that do not need to own every peak node year-round, renting Mac capacity from JexMac can provide a more flexible test path: keep the fixed baseline for critical work, then validate a temporary Mac against the real workflow, signing boundary, queue target, and recovery procedure. Start with the JexMac order options only after the scenario matrix shows which capacity is genuinely burst-only.

FAQ

Can a self-hosted Mac Runner scale automatically with GitHub Actions?

It can, but GitHub Actions does not automatically create, boot, secure, and destroy your physical or rented Mac hosts. A scaling controller must read queue signals, provision capacity through your infrastructure, register a temporary runner, and remove or quarantine the host after the job. Runner Scale Set Client can connect to the relevant API flow, but it remains a Public Preview project and does not replace Mac infrastructure automation.

Should Xcode CI use fixed Mac Runners or temporary runners?

Use fixed capacity when the workload is stable, the repository count is small, and toolchains, simulators, caches, or private network access need persistent maintenance. Use ephemeral capacity when release peaks, repository sharing, or trust boundaries create strong isolation requirements. For most teams, a fixed baseline for routine builds plus temporary capacity for predictable bursts is easier to operate than a full replacement.

Does Runner Scale Set Client support macOS nodes?

The official project documents a custom elastic runner approach that can include macOS. Its role is to connect to the Runner Scale Set API and produce temporary runner configuration. It does not supply a Mac host, install macOS, clean the machine, or guarantee recovery after a failed job. Those responsibilities stay with the infrastructure and security workflow around the client.

How can Mac Runner scaling prevent cross-repository contamination?

Separate runner groups and labels by trust level, Xcode version, signing access, and task type before adding capacity. Restrict each group to the repositories that require it, and treat temporary registration as different from host cleanup. Rebuild or wipe the Mac when appropriate, revoke credentials, preserve external logs, and test a failed-job path rather than checking only successful registrations.

Should a release peak use permanent Mac capacity or rented Macs?

Compare the peak duration with the idle period between releases. Permanent nodes are easier when signing state, private dependencies, and toolchains need continuous care. Temporary rented Macs are more suitable when the extra capacity is needed only for a defined release window and the workflow can inject credentials, install dependencies, collect logs, and remove access reproducibly. Validate with a real workflow before changing the baseline.

Bare metal · 1–5 min delivery

Choose a Dedicated Mac Runner for Every Build

Deploy a dedicated physical Mac mini M4 with JexMac for stable CI workloads and consistent native performance.

Standard spec
ChipApple M4 · 38 TOPS
CPU10-core (4P + 6E)
Memory16 GB unified memory
Network1 Gbps dedicated
SLA99.9% uptime
Delivery1–5 min auto provision