Sergei Ozeranskii
Self-hosted runners or managed: the real cost
For CI on GitHub Actions the cost question comes up sooner or later. Compare the instance price with GitHub-hosted’s per-minute billing, and on paper your own runners look cheaper. But an instance is only compute. The total cost of CI ownership is three line-items — compute, operations and risk — and the cloud price list shows only the first; the difference hides in the other two.
We build managed runners for GitHub Actions, so in this comparison we’re an interested party. That’s why the cases where self-hosted wins are named below too. Numbers here are published ones only; no Total Cost of Ownership — not just the price of the resource, but the operations, maintenance and risk over its whole lifetime. totals or “X% savings” — run your own on the calculator.
Three execution models
GitHub Actions CI has three models:
- GitHub-hosted — GitHub’s runners, billed per minute rounded up. Zero operations, but minute rounding and less control over the environment.
- Self-hosted — your own runners on your own hardware or cloud. Maximum control, but operations and security are entirely yours.
- Managed (tempus.build among them) — someone else’s runners as a service, but with the same
simplicity as GitHub-hosted: you change one
runs-online. You pay for execution; operations are the service’s job.
The rest is about the two poles: self-hosted and managed.
What self-hosted actually costs
The “instance for $N an hour” price tag covers only compute. Under it sits everything paid for in team time and idle capacity:
- Idle / always-on. Cloud instances and nodes are billed while running, not while executing a job. So you pay for the gap between builds and for headroom against peaks. CI is bursty by nature: a morning surge, quiet nights. That unevenness is what turns into paid idle time.
- Autoscaling. To avoid paying for a permanent peak, you need autoscaling. The standard OSS answer is ARC (actions-runner-controller), GitHub’s Kubernetes operator that autoscales self-hosted runners on demand. But that’s a cluster, the controller itself, runner scale sets, webhooks, RBAC — all of which you have to stand up, upgrade and maintain. Platform-team work, not a one-off install.
- Image build and patching. Someone builds the runner images, keeps toolchains and runtimes current, rebuilds for security patches and stops end-of-life versions from piling up. A continuous stream of work, not “set and forget”.
- Isolating untrusted code. CI runs someone else’s code — from PRs, from dependencies. Doing it safely takes VM-level isolation, Outbound network traffic from a runner — pulling dependencies and images. Clouds bill for it, and it has to be controlled for security. control, behavioural monitoring and A single-use runner for one job: created, runs, destroyed. Nothing survives the job boundary.. Self-hosting on shared, persistent runners opens the door to breakout and lateral movement. That’s not our take: GitHub itself advises against self-hosted runners on public repositories (opens in new tab) and recommends ephemeral runners — precisely because of untrusted code in PRs. (How that boundary works — in the Kata isolation deep-dive.)
- Cache infrastructure. Build speed rests on a dependency cache next to the runners (pull-through for npm/pip/docker, CAS). Without it every build pulls from the public internet — slower and pricier on Outbound network traffic from a runner — pulling dependencies and images. Clouds bill for it, and it has to be controlled for security..
- On-call. Uptime, upgrades, incidents and capacity all have an owner. A recurring human cost that a naive “by the VM price” comparison leaves out entirely.
Add these line-items up, and the “cheaper” from the instance-price comparison often disappears already at a mid-size team — one with no dedicated platform group to carry all this operational work.
How pricing works at tempus.build
Managed takes this operational cost off your team — images, patches, capacity, on-call and isolation are the provider’s job. In return you take on a dependency of your own (the provider’s uptime and SLA, a fixed shape catalogue, a trust boundary) — which is why the cases where self-hosted wins are named below.
The billing model changes too:
- Per second, no round-up. A 75-second job costs 75 seconds. GitHub-hosted rounds every job up to a whole minute — on short, frequent jobs that adds up.
- Execution only — no idle. You don’t pay for the gap between builds or for peak headroom: capacity and autoscaling are our concern, not a line on your bill.
- The delay to bring up a fresh environment (a VM or runner) before a job can start. A warm pool hides it at the cost of idle capacity. isn’t billed. The meter starts once the job is already executing; the seconds to boot a clean VM are on us. The warm capacity for peaks is ours too — a Pre-booted idle runners kept ready to pick up a job instantly. They remove cold start, but you pay for them while they wait. on our side.
- Prepaid — a spend ceiling is built in. The balance is topped up in advance and drawn down per second; you can’t spend past your balance, and there’s no surprise invoice at month’s end. The balance doesn’t expire.
- The price is baked into the label.
tempus-ubuntu-24.04-4coreis always$0.008/min, in any repository. Whatever you pick inruns-onis what you pay — no hidden multipliers.
Published rates (2 → 16 cores, RAM 1:4 to vCPU):
runs-on label | Resources | Rate |
|---|---|---|
tempus-ubuntu-24.04-2core | 2 vCPU / 8 GB | $0.004/min |
tempus-ubuntu-24.04-4core | 4 vCPU / 16 GB | $0.008/min |
tempus-ubuntu-24.04-8core | 8 vCPU / 32 GB | $0.016/min |
tempus-ubuntu-24.04-16core | 16 vCPU / 64 GB | $0.032/min |
The 4-core rate ($0.008/min) is cheaper than a comparable GitHub-hosted larger runner; billed in US
dollars, another currency on request. GitHub’s exact prices and multipliers are in the
official docs (opens in new tab) (on public
repositories standard runners are free — this is about private ones). On small volumes private repos can
fit within GitHub’s included minutes — which is why we say “work it out on your volume” rather than
promising savings to everyone. What it comes to for you — on the calculator; there’s no
universal “X% cheaper”, it all depends on the pipeline.
The calculator runs on the assumptions you enter. Coverage runs on the facts: sign up on the platform, install the GitHub App (opens in new tab) — and from your real GitHub Actions history it shows what the same runs would have cost on tempus.build runners. Without moving a single job to our runners.
On top of that, spend control: budgets with alerts and a hard stop, spike notifications, optional auto-recharge. You can start with a welcome $5 on the balance — no card required (personal accounts; for organizations the bonus balance is credited on request). That’s roughly 10 hours of a 4-core runner.
Comparison by axis
| Axis | Self-hosted | tempus.build (managed) |
|---|---|---|
| Billing model | for provisioned capacity (often always-on) | per second of execution, no round-up |
| Idle | you pay for idle and peak headroom | not billed |
| Operations | cluster, ARC, images, patching, on-call | on the service side |
| Scaling | you build and tune it (ARC) | elastic by default |
| Cold start | you weigh a warm pool against its cost | managed; not billed |
| Isolation | your responsibility, easy to get wrong | VM per job + egress control + behavioural monitoring |
| Supply-chain | you attest images yourself | signed images + SBOM + SLSA, open-source |
| Cache | you build and run it | colocated dependency cache included |
| Time to value | days–weeks to a safe launch | one runs-on line, rollback the same |
Where self-hosted wins
Managed isn’t always the right answer. Self-hosted is stronger when:
- You need full control and your own hardware — GPU, ARM, Windows/macOS, your own images, special toolchains. tempus.build today (MVP) is Ubuntu 24.04 x64 only, with a fixed catalogue of shapes.
- Strict data requirements — data residency, isolation in your own VPC or perimeter, air-gap. Your runners run where you say; a managed service is a third party inside the trust boundary.
- Steady 24/7 saturation. If a node is busy at nearly 100% around the clock, your own hardware at cost can beat any per-unit managed price. The per-second model wins on uneven CI, not on flat full utilisation.
- Vendor independence — no dependence on someone else’s uptime.
The dividing line: uneven CI + a small team + wanting zero operations → managed; steady 100% utilisation + strict residency + special hardware → self-hosted.
Trying tempus.build
Getting in and out is cheap by design:
- Switching in — one line.
runs-on: ubuntu-latest→runs-on: tempus-ubuntu-24.04-4core. The rest of the workflow doesn’t change. - Switching out — one line too. Put
ubuntu-latestback and you’re on GitHub-hosted again. The balance is refundable; you can leave any time. - Isolation like a separate machine. Every job runs in its own single-use VM, destroyed on completion. The runner image is open-source (tempusbuild/runner-images (opens in new tab)) — you can build and check it yourself; how the isolation works is on the Security & isolation page and in the Kata isolation deep-dive.
- A welcome $5 on the balance, no card — run your own pipelines and look at the real numbers before the first top-up.
Don’t take our word for it — work it out on your own volume and compare it with what your own operations cost you.