Every job gets a fresh EC2 instance in your own AWS account, on Spot,
for 5–15× less than GitHub charges. AWS bills you for the compute at
cost, and RunsOn is a yearly license, priced by the runners you launch
a month (one per job), that never meters your minutes.
Setup is one CloudFormation stack and about ten minutes, with no
Kubernetes cluster to keep alive. Then it just runs.
card at checkout, nothing charged for 15 days · then from €300 / $350
a year · free for non-commercial use
Running 3M+ jobs a day for 900 companies, including Cursor,
Tripadvisor and the Apache Software Foundation.
the label is a query — pick constraints, resolved at launch
.github/workflows/ci.ymlyaml
# the label is a query — each line one constraintjobs:
build:
runs-on:
- runs-on=${{ github.run_id }}
- cpu=16
- family=c8i
- image=ubuntu24-full-x64
- extras=s3-cachesteps: [...]
→ resolves to c8i.4xlarge · spot + disk ·
$0.0056/mingithub-hosted 16cpu: $0.0420/min≈ 8× cheaper
Some of the 900 companies running RunsOn in production.
Same minutes. A different bill.
A month of heavy builds: 150,000 minutes on 16-core Linux runners. GitHub bills each minute at its own rate. On RunsOn the same minutes run on spot instances in your AWS account, billed by AWS directly, and the license is one flat line that doesn't move with them.
One month of CI billed two ways, for 150,000 minutes of 16-core Linux jobs. GitHub-hosted: $6,300.00. RunsOn: $673.11, of which $598.05 is EC2 spot, $45.89 is EBS and $29.17 is a flat license. The license is on the bill before any job runs; GitHub's bill passes RunsOn's, license included, after 774 minutes.
ci-bill · one month, same minutes
day 30/30
github-hosted $6,300.00every minute, at GitHub's rate
runs-on · your aws account $673.11aws bills the minutes · license flat
$0$2k$4k$6k
$6,300$673$5,626.89 apart
day 1weekends shadedday 30
github-hostedGitHub-hosted bill for the month, $6,300.00 in total
16-core Linux runner150,000 min × $0.042
$6,300.00$6,300.00
aws + runs-on licenseAWS bill and RunsOn license for the month, $673.11 in total
EC2 spot · 16-core Linux150,000 min × $0.003987
$598.05$598.05
EBS gp3 · 30 GB per jobprorated over the same minutes
$45.89$45.89
RunsOn license flat$350 a year ÷ 12
$29.17$29.17
month closed150,000 min on both bills · $5,626.89 apartthe license is already on the bill: $29.17GitHub's meter passes RunsOn'sthe license stays at $29.17150,000 min on both bills · $5,626.89 apart
Worked example: the calculator's “Heavy Docker builds” preset over a 30-day month, 22 weekdays (weekends shaded). GitHub list price for its 16-core Linux runner; larger runners get no included minutes. AWS spot in us-east-1 (7-day average of the cheapest zone, as of Oct 5, 2026), plus a 30 GB gp3 disk per job; on-demand fallbacks cost more. Starter license ($350/yr, under 50k runners a month) shown as a twelfth; the control plane (a few dollars a month) is not included. Run your own numbers →
The same 150,000 minutes on a hosted runner vendor's 16 vCPU Linux x64 runner, at list price before free minutes: $2,400.00 at Ubicloud premium ($0.016/min) and $4,800.00 at Avrea, Blacksmith, StarSling or WarpBuild ($0.032/min). hosted runners compared →
On real Rust, TypeScript and Docker builds, RunsOn had the lowest cost per build in all three, ahead of Ubicloud, at the EC2 cost each RunsOn job measured on spot, on-demand fallbacks included (license and plan fees aside). GitHub-hosted runners were the slowest or second-slowest of 8–9 providers in every build. Run by RunsOn, which sells one of the runners measured.every runner, build and run →
What changes when you switch.
From GitHub-hosted runners, you keep the workflow and change the
bill. From a hosted runner vendor, the runners move into your own
AWS account. From Actions Runner Controller, you keep self-hosting
and drop the cluster.
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.
01
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.
1–96cpux64 · arm64 · gpuspot → on-demand
02
Cache restores 2.1–2.2× faster
Add extras=s3-cache to the label and a
runs-on/action@v2 step, and
actions/cache is backed by an S3 bucket in
your account, in the same region and VPC. Your cache steps stay as
they are.
Restoring 4 GB with actions/cache, the median RunsOn runner against GitHub-hosted at the same size: 27s against 59s at 2, 19s against 41s at 4, 15s against 33s at 8 vCPU. Run by RunsOn, which sells one of the runners measured.cache benchmark →
no size capin-VPC restores
03
Nested virt, both OSes
KVM for Linux, Hyper-V for Windows — nested virtualization is just a
label. Android emulators, VM-based e2e suites, Windows containers:
they run.
“By leveraging AWS with ECR, RunsOn helped cut our cache restore and image pull times by 80% and 60% respectively.”
Ruffin White — Senior Robotics Engineer, Dexory
“We've been using Actions Runner Controller on EKS, but hit a number of scaling issues, job pickup delays, and job cancellations. … We started trialing RunsOn … and have been thoroughly impressed.”
David Moran — Lead DevSecOps Engineer, SmithRx
“Less than 10 min to test, install and use the product. … The cache download speed is blazing fast thanks to amazon s3 endpoint.”
No. The runner images are ported from GitHub's own templates, so actions, cache steps and secrets keep working as they are. The migration is one line: runs-on: ubuntu-latest becomes runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64. Linux x64 and arm64, Windows and GPU are all included, and GitHub Enterprise Server is supported through the Terraform module.
02Can I switch one job at a time?+
Yes. The label is per job, so anything still on 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.
03How fast does a job start?+
In the public burst benchmark, 15 jobs queued at once, a RunsOn job's median wait from queued to running was 16–22s, depending on the runner type (28 x64 types measured). Hot warm pools bring that under 6 seconds where it matters. And since the instance is whatever size you asked for, the job itself finishes sooner. Run by RunsOn, which sells one of the runners measured: method, runs and raw results.
04Does Docker work?+
Yes. Each job gets the whole VM, so Docker, docker-in-docker and compose behave as they do on any EC2 instance. Docker layer caching is built in.
05Is it safe to run inside my AWS account?+
That's the point of it. Every job gets a fresh EC2 instance that is destroyed when the job ends: nothing shared, nothing persistent. Code, secrets, caches, logs and the GitHub App credentials never leave your account. The control plane runs in your account on Fargate under a limited IAM role. With Flex, GitHub posts job webhooks to an API Gateway endpoint in your account, which the built-in WAF can restrict to GitHub's IP ranges. Fleet, installed with the Terraform module, pulls jobs from GitHub instead and has no inbound endpoint at all. The full model is on the security page.
06What does leave my account?+
Two small flows to 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.
07What does it need from my AWS account?+
An AWS account where you have admin rights to create the stack, and someone who can install a GitHub App on the org, usually an owner. The CloudFormation stack creates the rest in about ten minutes: its own VPC, the cache bucket, IAM roles and the control plane, which runs on Fargate. For an existing VPC, GitHub Enterprise Server or IAM permission boundaries, use the Terraform / OpenTofu module instead. One license covers as many stacks as you want: production, staging, another region.
08What happens when spot capacity dries up?+
RunsOn tries spot first and falls back to on-demand when capacity is unavailable, at a 2–3s launch penalty. A job interrupted mid-run is retried once on an on-demand instance by default. You can pin any job to on-demand from the label, and a circuit breaker moves the whole stack to on-demand when interruptions spike.
09What does it cost beyond the license?+
Your AWS bill: spot instances for the minutes your jobs actually run, plus a control plane that costs a few dollars a month. There is no markup on compute, and your existing AWS credits and commitments apply. The license is priced by the number of runners you launch, one per job, never by the minute: €300 / $350 a year under 50k runners a month, €900 / $1,050 under 200k, €1,800 / $2,100 under 500k and €3,600 / $4,200 from 500k. Per-job cost reporting is built in, and the calculator does the math against your current GitHub bill.
10How locked in am I?+
As little as it gets. Leaving is the same one-line label change in reverse. Then you delete the stack, empty and delete the two S3 buckets it keeps (cache and access logs), and remove the GitHub App; the uninstall page has the steps. The license is one annual fee per legal entity, with no per-minute meter and no seats.
11How can the license be this cheap?+
RunsOn is bootstrapped: paid for by its customers, not investors, and it owns no servers. AWS bills you for compute at cost, so the license only has to pay for the software, and it never meters your minutes. Support comes from the people who write the code: email on every commercial license, community Slack for everyone, and a private Slack Connect channel on Enterprise. Fixes often ship within days. And since the whole stack runs in your account with the license check outside the job path, your CI doesn't depend on any infrastructure of ours staying up.
Three steps. One line to migrate.
The CloudFormation stack takes about ten minutes. Then the first job
lands on a spot instance in your own account.
01
Deploy the stack
One CloudFormation stack creates its own VPC, the cache bucket, IAM
roles and the control plane. For an existing VPC, GitHub Enterprise
Server or IAM permission boundaries, use the
Terraform / OpenTofu module;
Fleet installs with its own
Terraform module.
02
Connect the repo
Register the private GitHub App from the stack's outputs; on an
org, that usually takes an owner. Runners are registered per job,
and none waits idle between jobs.
03
Change one label
Swap a single line in your workflow. Every existing action, cache
step, and secret keeps working untouched.
A job is queued, an instance boots in your account, the job runs,
and the instance is terminated. In the burst benchmark, the median
wait from queued to running was 16–22s (run by RunsOn, which sells one of the runners measured).
If GitHub must not call into your account at all,
Fleet, installed with the
Terraform module, runs the same loop pull-based: no inbound webhook,
no public endpoint.
the trial runs the real product in your account · card at checkout,
nothing charged for 15 days · then from €300 / $350 a year ·
run the numbers on your bill