Route jobs
Configure workflows
Configure a local-infrastructure route and GitHub-hosted fallback in your existing workflow.
Your workflow’s runs-on selects a job’s execution route. This guide configures local infrastructure
with GitHub-hosted fallback while keeping your build and test steps. Other jobs in the
workflow can use different providers.
For a direct Cloudflare route, see Cloudflare runners. To compare providers and change a job’s default through Mirage-generated pull requests, use Compare CI providers.
Change runs-on
Start with an existing build or test job. Keep its steps and replace its GitHub-hosted
runner label with the expression for the same operating system and architecture. For a job
that currently uses ubuntu-24.04:
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-x64' || 'ubuntu-24.04' }}On the first attempt, GitHub sends the job to Mirage. If Mirage needs to use fallback, it requests a second attempt of the same workflow; the expression selects GitHub’s runner for that attempt. There is no extra setup job or Mirage action to add.
Runner labels
| Job environment | Mirage label | GitHub fallback |
|---|---|---|
| Linux x64 | mirage-linux-x64 | ubuntu-24.04 |
| Linux arm64 | mirage-linux-arm64 | ubuntu-24.04-arm |
| macOS arm64 | mirage-macos-arm64 | macos-26 |
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-arm64' || 'ubuntu-24.04-arm' }}runs-on: ${{ github.run_attempt == '1' && 'mirage-macos-arm64' || 'macos-26' }}Choose the architecture your tools support. Linux x64 on an Apple-silicon Mac needs Rosetta; native macOS needs an enabled and ready macOS runner profile. The machine’s details page lists each profile and any setup still required.
Tools, secrets, and caches
Mirage’s runner image has its own toolchain; it does not include everything from GitHub’s hosted images. Use setup actions or installation steps to select the versions your project needs, and install your dependencies before building or testing.
Jobs start in fresh environments. Use checkout to fetch your code, GitHub Actions artifacts to pass files between jobs, and cache actions for dependencies. Keep secrets in GitHub Actions and reference them as you already do. Tools and files installed in your Mac’s user account are not automatically available inside a job.
Linux runners on Macs support Docker commands, service containers, job containers, and Docker container actions. Cloudflare runners have different limits and do not support those Docker features.
Parallel jobs
Each running job needs a slot. A Mac starts with one shared slot across its profiles and
accounts. If you submit several jobs at once, insufficient capacity can trigger fallback.
Add machines, raise concurrency when the host has enough resources, or use needs to run
jobs in sequence:
jobs:
first:
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-arm64' || 'ubuntu-24.04-arm' }}
steps:
- run: echo "First job"
second:
needs: first
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-arm64' || 'ubuntu-24.04-arm' }}
steps:
- run: echo "Second job"Each job still gets a fresh environment. A dependency controls execution order; it does not share a working directory.
How fallback works
If your machines cannot take the job or a runner has an infrastructure failure, Mirage can cancel attempt 1 and request one rerun of the whole workflow. Attempt 2 uses your configured fallback. GitHub keeps both attempts under the same run ID.
- A failed test or build is a CI result and does not trigger an infrastructure retry.
- A manual rerun also increments the attempt, so the expression selects GitHub-hosted runners.
- Fallback needs Mirage and GitHub to be reachable. A Mirage outage can leave a job queued.
- GitHub-hosted jobs use your GitHub Actions allowance or billing.
Run only on your machines
If you want every attempt to target Mirage, use a literal label:
runs-on: mirage-linux-arm64This label cannot switch to a GitHub-hosted runner on a rerun. If no eligible machine is available, the job cannot complete there. Use the attempt expression above when you want automatic hosted fallback.