Skip to content

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-on line. 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.
A vertical stack of cost line-items: the highlighted «Compute price» on top (visible in the price), below it the hidden ones: idle and always-on capacity, autoscaling (ARC on Kubernetes), image build and patching, isolating untrusted code, cache infrastructure, on-call and incidents; a brace on the right marks the total cost of ownership.
Compute price is just the top row. The total cost of owning self-hosted CI adds operations and risk: idle, autoscaling, images, isolation, cache, on-call.

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-4core is always $0.008/min, in any repository. Whatever you pick in runs-on is what you pay — no hidden multipliers.

Published rates (2 → 16 cores, RAM 1:4 to vCPU):

runs-on labelResourcesRate
tempus-ubuntu-24.04-2core2 vCPU / 8 GB$0.004/min
tempus-ubuntu-24.04-4core4 vCPU / 16 GB$0.008/min
tempus-ubuntu-24.04-8core8 vCPU / 32 GB$0.016/min
tempus-ubuntu-24.04-16core16 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

AxisSelf-hostedtempus.build (managed)
Billing modelfor provisioned capacity (often always-on)per second of execution, no round-up
Idleyou pay for idle and peak headroomnot billed
Operationscluster, ARC, images, patching, on-callon the service side
Scalingyou build and tune it (ARC)elastic by default
Cold startyou weigh a warm pool against its costmanaged; not billed
Isolationyour responsibility, easy to get wrongVM per job + egress control + behavioural monitoring
Supply-chainyou attest images yourselfsigned images + SBOM + SLSA, open-source
Cacheyou build and run itcolocated dependency cache included
Time to valuedays–weeks to a safe launchone 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-latestruns-on: tempus-ubuntu-24.04-4core. The rest of the workflow doesn’t change.
  • Switching out — one line too. Put ubuntu-latest back 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.

← back to the blog