v3.4 changelog quickstart →

Self-hosted GitHub Actions runners, done properly.

Spot compute billed at cost by AWS, a yearly license that never meters your minutes, one CloudFormation stack to install. Then it just runs.

Free for 15 days. Step one gets you a trial key: we ask for a card and don't charge it. Then from €300 / $350 a year, free for non-commercial use. Pricing

.github/workflows/ci.yml the whole migration
build:−  runs-on: ubuntu-latest+  runs-on:+    - runs-on=${{ github.run_id }}+    - family=m8+r8+    - cpu=4+    - extras=s3-cache+  steps:+    - uses: runs-on/action@v2    - ...

Any 8th-gen general-purpose or memory-optimized instance with 4 vCPU, whichever has spot capacity at launch. actions/cache restores from S3 in your VPC.

→ m8a.xlarge or similar · from $0.0015/min github-hosted 4cpu: $0.0120/min 8× cheaper
every job label →

150,000 minutes: $6,300 on GitHub, $692 on RunsOn.

A month of 16-core Linux builds. On RunsOn, AWS bills the minutes at cost and the license is one flat line.

9× less

One month of CI billed two ways, for 150,000 minutes of 16-core Linux jobs. GitHub-hosted: $6,300.00. RunsOn: $691.56, of which $616.50 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 776 minutes.

ci-bill · one month, same minutes
GitHub-hosted bill for the month, $6,300.00 in total
16-core Linux runner 150,000 min × $0.042 $6,300.00
AWS bill and RunsOn license for the month, $691.56 in total
EC2 spot · 16-core Linux 150,000 min × $0.00411 $616.50
EBS gp3 · 30 GB per job prorated over the same minutes $45.89
RunsOn license flat $350 a year ÷ 12 $29.17
How this is counted 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 8, 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 →

Switching from GitHub-hosted runners, a vendor, or ARC

5–13× cheaper

Keep the workflow. Change the bill.

Same images, same actions, same cache steps. The jobs move to EC2 in your AWS account, at what AWS charges for the minutes.

price your own minutes →
dimension GitHub-hosted RunsOn
price per minute, at GitHub's rate AWS spot at cost, 5–13× cheaper
machines a fixed menu of sizes any EC2 instance, x64 · arm64 · GPU
cache 10 GB free per repo, more billed S3 in your VPC, no size cap
code runs on GitHub's infrastructure your AWS account, a fresh VM per job

Cache, Docker layers, spot fallback and nested virt come with the stack

Each one is a label away.

01

Cache restores 1.8–2.3× faster

Add extras=s3-cache and a runs-on/action@v2 step: actions/cache then reads and writes an S3 bucket in your account, in the same 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: 26s against 59s at 2, 19s against 37s at 4, 16s against 28s at 8 vCPU. cache benchmark →

no size capin-VPC

02

Docker builds that start warm

Turn on the ephemeral ECR registry in the stack, add extras=ecr-cache and point Buildx at type=registry: layers stay in your account, so the next build pulls them instead of rebuilding. type=gha and type=s3 work too.

ECR in your accountBuildKit cacheLinux

03

Spot, with a safety net

Jobs run on spot by default. With no spot capacity, the instance launches on-demand instead, and a job that loses its spot instance mid-run is rerun, with new capacity launched on-demand.

spot by defaulton-demand fallbackspot=false

04

Nested virt, both OSes

KVM on Linux, Hyper-V on Windows, from one label. Android emulators, VM-based end-to-end suites and Windows containers run as they would on a workstation.

KVMHyper-Vm8i · c8i · r8i

Also in the box: per-job cost reportingstatic egress IPswarm poolssticky disksyour own AMIsGPU

Overheard in CI channels

“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
“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
“Less than 10 min to test, install and use the product. … The cache download speed is blazing fast thanks to amazon s3 endpoint.”
Christopher Brookes — SRE
read all testimonials →

You probably have questions

Will it work?

Will my existing workflows break?
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 }}/family=m8+r8/cpu=4. Linux x64 and arm64, Windows and GPU are all included, and GitHub Enterprise Server is supported through the Terraform module.
Can 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.
How 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 17–23s, 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.
Does 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.

Is it safe?

Is 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.
What 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.
What 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.

What does it cost?

What 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.
What 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.
How 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.
How 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 Sponsorship, the Enterprise plan for sponsors, which also comes with the full source code. 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.
the long versions are in the docs →

Install takes about ten minutes

  1. 01

    Deploy in your account

    CloudFormation One stack, about ten minutes: its own VPC, the cache bucket, IAM roles and the control plane.

    Terraform / OpenTofu For an existing VPC, GitHub Enterprise Server, permission boundaries, or Fleet. Flex module · Fleet module

  2. 02

    Connect GitHub

    Install the private GitHub App from the stack's outputs. On an org, that usually takes an owner.

  3. 03

    Change one label

    Swap runs-on: ubuntu-latest for a RunsOn label. Actions, cache steps and secrets keep working.

Then, for every job, an instance boots in your account, runs the job, and is terminated. Two ways to run that loop. Flex vs Fleet →

Flex job lifecycle · 50 jobs coming and going, one fresh box each
0 instances up now 0 jobs done one fresh box per job, gone when it's done
~10 min setup

Then it just runs.

The real product, in your account, free for 15 days. Then from €300 / $350 a year. Run the numbers on your bill →