Custom runners & images
Define custom runner shapes and custom AMIs for RunsOn — per job in Flex (.github/runs-on.yml) or in the Terraform catalog for Fleet.
The built-in runners and images cover most workloads. When you need a specific instance shape, or your own AMI with internal SDKs, slow-changing toolchains, or security agents baked in, define a custom runner and/or a custom image.
The model is the same across products — only where you declare it and who selects it differ: in Flex workflow authors define and pick per job in .github/runs-on.yml; in Fleet the platform team curates a Terraform-owned catalog.
Custom runners
A custom runner is a named runner shape (CPU/RAM/family/image/extras/…) you reference instead of spelling everything out in the runs-on label.
Flex
Define runners in .github/runs-on.yml, then reference them with runner=<name>:
runners: gpu-type1: family: ["g4dn", "g5"] image: ubuntu24-gpu-x64 cpu: [4, 16] spot: price-capacity-optimized extras: ["s3-cache"] preinstall: | apt-get update && apt-get install -y my-tooljobs: build: runs-on: runs-on=${{ github.run_id }}/runner=gpu-type1Common fields: cpu, ram, volume, family, spot, image, ssh, extras, private, nested-virt, retry, preinstall, prerun, tags. See Repo-level config for the full reference.
Fleet
Fleet defines runner shapes in the Terraform runners map, exposes them through fleets, and workflows target the fleet label:
runners = { gpu = { family = ["g5.xlarge"] image = "ubuntu24-gpu-x64" extras = ["s3-cache"] }}
fleets = { gpu = { runner = "gpu" runner_group = "platform" }}See Runner fleets for the full catalog reference.
Custom images
Every runner launches from an EC2 AMI. Default runners use a public AMI managed by RunsOn; a custom image points RunsOn at your own AMI instead.
Flex
Define the image once in .github/runs-on.yml, then select it from workflow YAML (or from a custom runner’s image):
images: ci-ubuntu24: platform: linux arch: x64 owner: "123456789012" name: "ci-ubuntu24-*"jobs: test: runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/image=ci-ubuntu24Fleet
The same decision belongs in the Terraform-owned catalog:
images = { ci-ubuntu24 = { owner = "123456789012" name = "ci-ubuntu24-*" platform = "linux" arch = "x64" }}runners = { linux-ci = { family = ["c8i.large"] image = "ci-ubuntu24" }}fleets = { linux-ci = { runner = "linux-ci", runner_group = "platform" }}Image model
A runner image is an EC2 AMI plus metadata: platform, arch, owner, and either an exact ami ID or a name lookup pattern. The image must match the runner architecture and region — x64 runners need x64 AMIs, arm64 runners need arm64 AMIs, Windows runners need Windows AMIs.
The name pattern can include a wildcard (e.g. ci-ubuntu24-*); RunsOn then queries EC2 at launch time for the most recent matching AMI — the usual way to pick up nightly rebuilds without touching the workflow. Both Flex and Fleet images also support preinstall (runs as root before the runner agent) and prerun (just-in-time setup, useful with warm pools).
Use custom images for dependencies that change slowly: SDKs, compilers, language runtimes, large base Docker layers, internal tooling, or security agents. Keep fast-changing build outputs in caches instead.
Flex vs Fleet
Same runner and image model, same metadata fields; only the place where they’re declared and selected changes.
| Aspect | Flex | Fleet |
|---|---|---|
| Where defined | .github/runs-on.yml | Terraform module (runners/images) |
| Who selects | Workflow author, per job | Platform team, in the catalog |
Per-job ami= override | ✓ | — |
| Wildcard name lookup | ✓ | ✓ |
| Recommended for | Workflow-specific or experimental shapes | Shared standardized shapes for many repos |