Dynamic instance selection
The instance is the job. The label is a query — family, cpu, ram, image, volume — resolved against live spot capacity at launch. No pools to size, no scale sets to babysit.
Ephemeral EC2 runners in your own AWS account: any instance per job, picked by label, gone when the job ends. One CloudFormation stack to deploy, one line to migrate. Then it just runs.
15-day free trial · free for non-commercial use
the label is a query — pick constraints, resolved at launch
# the label is a query — each line one constraint jobs: build: runs-on: - runs-on=${{ github.run_id }} - cpu=16 - family=c7i - image=ubuntu24-full-x64 - extras=s3-cache steps: [...]
A job is queued, an instance boots in your account, the job runs, the instance is terminated. About 30 seconds from queued to running, and nothing waits around in between. If GitHub must not call into your account at all, Fleet runs the same loop pull-based: no inbound webhook, no public endpoint.
cheaper than GitHub-hosted runners — you pay AWS directly, no per-minute markup.
do the math on your bill →jobs every day — ephemeral runners launched and destroyed, one box per job.
vCPUs daily — from 1 to 896 per runner, across x64 · arm64 · gpu.
Instance choice, caching, nested virtualization: the parts a runner needs around it. They come with the stack, already wired, and you turn them on from the label.
The instance is the job. The label is a query — family, cpu, ram, image, volume — resolved against live spot capacity at launch. No pools to size, no scale sets to babysit.
Flip extras=s3-cache and
actions/cache is backed by an S3 bucket in
your account — same region, same VPC, no 10GB ceiling. Nothing else
in the workflow changes.
KVM for Linux, Hyper-V for Windows — nested virtualization is just a label. Android emulators, VM-based e2e suites, Windows containers: they run.
+ docker layer caching · per-job cost reporting · spot→on-demand retry · static egress IPs · warm pools · byo AMIs
The same workflow on Actions Runner Controller, then on RunsOn. One needs a cluster, a controller and an autoscaler. The other needs a label.
From GitHub-hosted runners, you keep the workflow and change the bill. From Actions Runner Controller, you keep self-hosting and drop the cluster.
| dimension | GitHub-hosted | RunsOn |
|---|---|---|
| price | per minute, at GitHub's rate | AWS spot at cost, 7–12× cheaper |
| machines | a fixed menu of sizes | any EC2 instance, x64 · arm64 · gpu |
| cache | 10GB per repo | S3 in your VPC, no ceiling |
| code runs on | GitHub's infrastructure | your AWS account, fresh VM per job |
| setup | none | one CloudFormation stack, ~10 min |
| dimension | ARC | RunsOn |
|---|---|---|
| prerequisite | a Kubernetes cluster, plus Helm | one CloudFormation stack, no cluster |
| scaling | scale sets on nodes you size | one EC2 per job, scales to zero |
| images | containers you build and patch | AMIs from GitHub's templates, kept current |
| windows & gpu | extra node groups and images | a label |
| idle cost | node pools sized for peak | none — nothing runs between jobs |
“Saved around 75% of our costs, and tests now run 5× faster on gigantic spot instances.”
Tim Dumol — Founding Engineer, Expedock
“After benchmarking a lot of tools, it's the best. Costs divided by 4 — thousands of jobs per day.”
Corentin Smith — CTO, Dashdoc
“Costs down 70%, CI runtime improved up to 80%. A clear win with virtually no downside.”
Théophile D. de Segonzac — Lead DevOps, Lingoda
The questions your security review, your finance team and your on-call rotation will ask. The long versions are in the docs.
ubuntu-latest keeps running on GitHub. Most teams move the slow, expensive jobs first and the rest when convenient. macOS jobs stay where they are: RunsOn is Linux and Windows on EC2, and the two coexist in the same workflow.runs-on.com, both over TLS: a license check (org name, region, license key, app version) and a per-launch telemetry event (region, instance type, boot timings, enabled features). Neither carries repository contents, secrets, or anything from the runner filesystem, and neither sits in the job's execution path.About ten minutes from an empty AWS account to the first job landing on a spot instance you own.
One CloudFormation template — or the official Terraform module. VPC, cache bucket, IAM, and the scheduler come up together.
Install the GitHub App on your org. RunsOn registers ephemeral runners on demand — nothing stays running idle.
Swap a single line in your workflow. Every existing action, cache step, and secret keeps working untouched.
# the entire migration, in one diffruns-on: ubuntu-latestruns-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x6415-day free trial · one flat annual license, see pricing
runs on your account · runs on spot · runs on arm64, windows, gpu · runs on one label