Skip to content
Latchkey

Self-Hosted vs Managed GitHub Actions Runners

Self-hosted runners look dramatically cheaper because the comparison usually counts only EC2 and ignores the idle time, the engineer, and the security boundary you just took ownership of.

The self-hosted case is easy to make on a spreadsheet: a c6i.large is a fraction of $0.006/min, so why pay a managed provider? The reason the spreadsheet misleads is that it compares a per-minute rate against an hourly instance that is billed whether or not a job is running.

A managed runner is billed only while a job executes. A self-hosted fleet is billed continuously and utilised intermittently, and CI load is extremely spiky: near-zero overnight, saturated at 11am. Sizing for the peak means paying for the trough.

Standard GitHub-hosted runners are free and unlimited on public repositories, and public repos get 4 vCPU and 16 GB rather than the 2 vCPU and 8 GB private repositories receive. No paid runner beats free, so everything below assumes a private repository past its included minutes.

The comparison people usually skip

Self-hostedManaged
Billed forInstance uptime, busy or idleJob execution time only
UtilisationTypically 10-30% on spiky CI loadEffectively 100%
Scale-outYours to build and operateIncluded
Runner imagesYou build and maintainMaintained for you
Security boundaryYour network and IAMProvider's isolation
Fork PR riskUntrusted code on your infrastructureIsolated per job
On-callYouProvider
Best atHigh steady volume, special hardware, residencySpiky load, small teams, no ops capacity

Compute the real number, not the instance price

The honest self-hosted cost is instance cost divided by utilisation, plus the engineering time to operate it. Utilisation is the term that decides the comparison and the one most estimates omit.

The arithmetic that matters
# effective cost per BUSY minute
#   = (instance $/hr / 60) / utilisation
#
# a $0.10/hr instance at 20% utilisation:
#   ($0.10 / 60) / 0.20 = $0.0083 per busy minute
#
# which is MORE than GitHub-hosted list at $0.006/min,
# before counting a single hour of engineering time.

The security trade is the part that is hard to reverse

  • A self-hosted runner executing a fork pull request runs untrusted code on your infrastructure. GitHub documents this as not recommended for public repositories, and it is the single largest risk in this decision.
  • Runners must be ephemeral. A reused runner leaks state between jobs, and a job that persists something malicious persists it for the next one.
  • Anything the runner can reach on your network, a compromised job can reach.

Where self-hosted genuinely wins

  • Steady, high, predictable volume where utilisation is actually high.
  • Hardware nobody rents by the minute: GPUs, specific CPU features, very large memory, macOS on owned hardware.
  • Data residency or private network access that a managed provider cannot offer.
  • You already operate a fleet for other reasons, so the marginal operational cost really is near zero.

How to evaluate a managed runner honestly

Runner vendors compete on a headline per-minute rate, and the rate is rarely what decides the bill. Measure the whole job, on your own pipeline, before committing.

  • Compare at equal machine shape. A cheaper per-minute rate on fewer vCPUs or less RAM is not cheaper per unit of work.
  • Check billing granularity. Per-minute rounding costs real money on a wide matrix of short jobs; per-second does not.
  • Include queue and boot time. A runner that is cheaper per minute but slower to start can cost more per merge.
  • Count your re-runs. If a meaningful share of your runs are retries of a failed job, you are paying for the same work twice at whatever rate you negotiated, and no rate card prices that.
  • Verify the free tier is recurring. A one-time credit is not a free tier.

The verdict

Spiky load, which is most teams: managed wins on true cost once you divide by utilisation, before counting operational time at all.

High steady volume with existing infrastructure expertise: self-hosted wins, and the gap widens with scale.

Special hardware or residency requirements: self-hosted or a BYOC provider, because managed cannot offer it at any price.

Public repositories: do not put self-hosted runners on them. Fork pull requests execute untrusted code on your infrastructure.

Frequently asked questions

Self-Hosted vs Managed GitHub Actions Runners?
The self-hosted case is easy to make on a spreadsheet: a c6i.large is a fraction of $0.006/min, so why pay a managed provider? The reason the spreadsheet misleads is that it compares a per-minute rate against an hourly instance that is billed whether or not a job is running.
Compute the real number, not the instance price?
The honest self-hosted cost is instance cost divided by utilisation, plus the engineering time to operate it. Utilisation is the term that decides the comparison and the one most estimates omit.
Which should I choose?
Spiky load, which is most teams: managed wins on true cost once you divide by utilisation, before counting operational time at all.

Related guides

References

Latchkey managed runners from $0.0025/min against $0.006 GitHub-hosted, with self-healing. Start free → 30-day trial · No credit card