Skip to main content

Self-Hosted GitHub Actions Runners vs Depot vs GitHub: The Real Math for Teams That Own Their Machines

12 min readDora NodaDora Noda
Share
On this page

A team burning 30,000 CI minutes a month pays GitHub about $180 for the privilege — or about $60 to run the same minutes on a single dedicated server it already owns. That 3x gap is the whole pitch for self-hosted GitHub Actions runners, and it is also the number most likely to mislead you, because the per-minute bill is only one of three prices you pay. The other two are speed and toil, and they point in opposite directions.

Depot sits in the middle of this triangle. It markets GitHub Actions runners at half GitHub's price with dramatically faster CPUs and caching, as a drop-in label swap. Owning the runner boxes sits at the far end: maximum savings, maximum responsibility. This post runs the concrete math for all three options at three team sizes, then prices the parts the rate card hides — ephemeral-runner security, cache locality, and the maintenance load — so you can pick based on your minute volume instead of vibes.

The rate card in September 2026

Start with verified numbers, because this rate card moved recently and most blog posts quoting it are stale.

GitHub-hosted Linux runners currently bill at $0.006 per minute for the standard 2-core x64 runner and $0.005 for the 2-core Arm64 runner, with larger runners scaling up from there (4-core at $0.012, 8-core at $0.022). Two details matter more than the headline rate. First, GitHub rounds every job up to the nearest whole minute, so a fleet of 20-second lint jobs bills at 3x its clock time. Second, these rates already include a price cut: on January 1, 2026 GitHub reduced hosted-runner prices by up to 39%, which is what took standard Linux from the long-standing $0.008 down to $0.006.

Depot's GitHub Actions runners start at $0.004 per minute for 2 vCPU and 8 GB of RAM, scaling linearly to $0.128 per minute for the 64-CPU monster. Billing is tracked per second, so those 20-second jobs cost what they actually consume. Depot's headline claim — up to 3x faster with 10x faster caching at half the cost of GitHub-hosted runners — is still on its docs page, but do the division against today's rate card: $0.004 versus $0.006 is a 33% discount, not 50%. The "half the price" framing dates from GitHub's old $0.008 rate. Still cheaper and (claimed) faster, but the gap narrowed in January and your spreadsheet should use the new numbers.

Self-hosted runners, meanwhile, cost $0 in GitHub fees. That deserves an asterisk with a history: in December 2025 GitHub announced a $0.002-per-minute platform charge for self-hosted runners starting March 2026, then shelved it indefinitely within about a day after community backlash. So your own boxes are still meter-free on the GitHub side — but the episode is a reminder to recheck the rate card every budgeting cycle rather than assuming today's free tier is a permanent fixture.

The math for a typical team

Now the core deliverable: monthly CI spend for a team running standard 2-core-equivalent Linux minutes, across GitHub-hosted, Depot, and one owned Hetzner AX-class dedicated box (Ryzen 8-core, 64 GB RAM, roughly $50–85 per month depending on the exact SKU — call it $60 for the math).

Monthly minutesGitHub-hosted ($0.006)Depot ($0.004)Own AX-class box (~$60 flat)
5,000$30$20$60
10,000$60$40$60
30,000$180$120$60

Three things fall out of this table. First, below roughly 10,000 minutes a month, do not buy a box for CI alone — the metered options are cheaper and you get zero maintenance. (GitHub's 2,000 free monthly minutes on private repos push the small-team breakeven even further out.) Second, the own-box breakeven sits at about 10,000 minutes against GitHub and 15,000 against Depot. Third, past breakeven the curves diverge hard: at 30,000 minutes the owned box costs a third of GitHub and half of Depot, and every minute beyond that is nearly free.

But minute volume is not the only variable. Job shape matters because of the rounding rules. A team whose CI is hundreds of sub-minute jobs (lint, typecheck, unit tests sharded per package) pays GitHub for far more minutes than it consumes, while Depot's per-second tracking bills the clock time. If your average job runs 40 seconds, GitHub's effective rate is closer to $0.009 per clock-minute — and the Depot breakeven drops by a third. Conversely, long Docker-build jobs that run 8–12 minutes each barely feel rounding at all.

The honest version of the table, then, is a range: count your billed minutes (not clock minutes — check the Actions usage report, which reflects rounding), then read across. If you are under 10k billed minutes, stay metered. Between 10k and 15k, Depot is usually the value sweet spot. Past 15–20k, an owned box starts winning on the bill — and the question stops being about price and starts being about the next two sections.

Where Depot still earns its margin

If an owned box is 3x cheaper at volume, why does anyone pay per minute? Because Depot is not really selling minutes — it is selling minutes that finish faster with no fleet to operate.

The concrete claims are faster CPUs (Depot advertises up to 3x faster runners than GitHub-hosted) and dramatically faster caching (10x faster cache operations than GitHub's cache service). These compound: CI wall-clock time is dominated by dependency installation and Docker layer pulls on cold runners, so a runner that is both compute-faster and cache-faster can turn a 9-minute GitHub job into a 3–4 minute Depot job. That speedup is itself a discount — fewer billed minutes per run — on top of the lower per-minute rate. Teams migrating with a one-line runner-label change commonly report both a lower bill and a faster feedback loop, which is a rare combination.

There is a real ceiling to this story, though. Depot's cache is fast, but it is still a remote cache: every job downloads its dependency tree and build layers over the network on a cold machine. A self-hosted runner with warm local caches — a persistent package store, a warm Docker layer cache, an sccache backend sitting on the same LAN — skips the download entirely for cache hits. At high job frequency on a stable dependency tree, warm-local beats fast-remote, sometimes by minutes per job. Depot wins the cold-start race; owned boxes win the steady-state race. Your dependency churn rate decides which race you are running.

So Depot's margin is earned, not extracted: it is the price of a faster meter with no ops burden. Whether that margin beats an owned box depends on whether your team values engineer-minutes waiting on CI more than the $60–120 monthly delta — for most teams past 20k minutes, the honest answer is that the box wins on both, and the only remaining question is toil.

What owning the boxes really costs

Here is the bill the rate card never shows. Running your own GitHub Actions fleet on Kubernetes via actions-runner-controller (ARC) means paying in four currencies: setup, security discipline, cache engineering, and ongoing maintenance.

Setup is the smallest cost. ARC runs each job in an ephemeral pod — one job per runner, then the pod is destroyed — and scales the runner pool to zero when idle. The manifests are well documented, and a competent platform engineer can stand up a basic ARC deployment in a day. The ongoing maintenance is the real line item: runner images to rebuild, ARC itself to upgrade, Kubernetes node pools to keep healthy, and CI failures to triage when the problem is your fleet rather than your code. Budget a few hours a month of someone's attention forever, and do not self-host CI if nobody owns that pager.

Security discipline is the cost teams most often underestimate. GitHub's own docs warn that self-hosted runners have no guarantee of running on ephemeral, clean machines — ARC gives you that guarantee architecturally, but only if you actually run ephemeral mode and only if you segregate workloads. The hard rule: untrusted code — pull requests from forks — never runs on your self-hosted fleet. The "pwn request" attack class (a malicious PR combined with pull_request_target checking out attacker-controlled code) can exfiltrate secrets and poison shared caches in a single job execution, ephemeral or not. The standard posture is fork PRs on GitHub-hosted runners, trusted push-to-main and release builds on your own boxes.

Layer on the usual hardening — non-root runner user, dropped Linux capabilities, NetworkPolicies that allow only GitHub and your registries, blocked cloud metadata endpoints — and treat the runner namespace as hostile-adjacent infrastructure, not just another workload.

Cache engineering is the cost that converts directly into the speed win from the previous section. Out of the box, ephemeral ARC pods are as cold as GitHub-hosted runners — arguably colder, since you do not even get GitHub's cache service for free. The teams that beat Depot on wall-clock time do it deliberately: a shared S3-compatible object store backing sccache for compiled artifacts, namespace-local persistent volumes mounted as package-manager caches, and pre-warmed runner images carrying the toolchain. None of this is exotic, but it is all yours to build, monitor, and keep from growing stale. Skip it and your owned fleet is cheaper but slower than Depot — the worst of both options.

Add it up and the total cost of ownership looks like this: ~$60 per month per box, plus a day of setup, plus a few hours of monthly maintenance, plus one careful security review of your workflow triggers, plus a cache layer you design yourself. For a team past 20k minutes with someone who already operates Kubernetes, that is a bargain. For a team without that person, it is a trap — Depot's per-minute margin is cheap compared to a compromised runner fleet or a CI outage during release week.

One cluster or two?

The last question is architectural: if you already run a Cluster-API-managed fleet for your PaaS, should CI runners live in the same cluster or a separate pool? The answer depends on which cost you are optimizing.

Folding runners into the existing PaaS cluster makes the marginal cost of CI nearly zero. Runner pods scale to zero when idle and burst onto spare capacity when jobs queue — you are amortizing CI across machines you already pay for, which beats even the $60-box math above. ARC's scale-to-zero behavior is what makes this work: idle CI costs you nothing but the controller's own footprint. For a platform team whose cluster already has headroom (and most owned fleets run well below saturation), this is the cheapest possible CI that still runs on owned hardware.

The counterargument is blast radius and noisy neighbors. CI workloads are the most adversarial tenants you will ever schedule: bursty CPU that saturates every core it can see, disk-hungry builds, and a failure mode (cache poisoning, resource exhaustion) that can take down neighboring pods. Running them in the same cluster as customer-facing workloads means a runaway build matrix can starve the workloads that actually serve traffic — unless you enforce the isolation properly: dedicated node pools with taints so runners land only on runner nodes, resource quotas on the runner namespace, and priority classes that always preempt CI before serving workloads.

The decision rule that falls out of this: share the management plane, separate the blast radius. Run ARC in the same Cluster API management cluster so you operate one control plane, but give runners their own MachineDeployment — their own nodes, their own scaling policy, their own failure domain. You keep the marginal-cost amortization (the nodes are still machines you own, scaled to zero when idle) without letting a fork bomb in a test suite page the on-call for customer traffic. Only split into a fully separate cluster when compliance or tenant isolation demands it; for most teams, namespace-plus-nodepool isolation inside one fleet is the sweet spot.

Pick by minute volume, then by toil budget

The decision compresses to two questions. First, how many billed minutes do you burn a month? Under 10k: stay on metered runners, and take GitHub's free tier seriously. 10k–15k: Depot is the value pick — cheaper than GitHub per minute, faster per job, zero ops. Past 15–20k: an owned box (or spare capacity on your existing fleet) wins the bill by 2–3x and can win wall-clock too, if you build the cache layer.

Second, who owns the pager? If nobody on your team operates Kubernetes today, Depot's margin is the cheapest insurance you will ever buy — self-hosted CI without an owner is how you get a crypto miner in your runner namespace. If someone already runs your fleet, ARC plus ephemeral runners plus fork-PR segregation is a weekend project with a permanent payoff.

Either way, the meta-lesson is the same one every self-hosting decision teaches: metered services charge you for the privilege of not thinking about infrastructure, and that privilege has a price curve. Find where your volume sits on it, and spend the savings on the parts of the platform that actually differentiate you.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex