---
title: "What self-hosted CI actually costs"
description: "Calculate self-hosted CI cost with an editable model for idle capacity, control planes, storage, retries, and engineering time. Compare cost per successful workflow."
url: https://9apes.com/blog/self-hosted-ci-cost/
---

# What self-hosted CI actually costs

A lower compute rate does not guarantee cheaper CI. In our illustrative model,
a busy self-hosted fleet costs $685 less per month than GitHub-hosted runners
with established operations, but $365 more when maintaining it takes more work.
The machines and workload stay the same. Engineering effort changes the result.

The [editable cost model](/downloads/ci-lab/cost-model.zip) separates infrastructure,
recurring labor and setup. These are hypothetical scenarios, not measured bills
or performance benchmarks. They use a September 2026 pricing snapshot and
editable assumptions; refresh the inputs before making a decision.

## Compare cost per successful workflow

Count the cost of every attempt, including failures, retries and canceled jobs.
Divide by successful workflow outcomes, not individual jobs:

```text
cost per successful workflow =
  (compute + supporting services + operations + amortized setup)
  / successful workflow outcomes
```

A workflow with six jobs still delivers one outcome. A failed attempt followed by
a successful retry contributes both attempts' costs and one success. Compare the
same workload, test coverage and billing period on both sides.

For self-hosting, count each instance's running time once, including boot,
registration, idle waiting and shutdown. Do not add job execution charges on top
of the full node bill. Two concurrent ten-minute jobs consume twenty job-minutes
but only ten active node-minutes.

The supplied billing assumptions round hosted jobs individually to whole minutes
and EC2-like instance sessions by the second with a one-minute minimum. Apply
included usage once across the account, using only the allowance remaining after
other repositories. The README links the [GitHub billing rules](https://docs.github.com/en/billing/concepts/product-billing/github-actions)
and [EC2 billing rules](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-on-demand-instances.html);
check the actual runner and purchase option before reusing these settings.

## What belongs in a managed runner cost comparison?

Include billed compute across all attempts, the remaining included usage, recurring plan fees, cache and artifact storage, network charges, and engineering effort. Check billing granularity and whether a failed or canceled job still incurs usage. Compare equivalent successful workflow outcomes, then report elapsed completion time separately from the billable duration of parallel jobs.

For a managed service, ask which operational tasks remain with your team: image compatibility, workflow configuration, permissions, incident diagnosis, and usage review. For a fleet in your own account, include idle capacity and infrastructure operations as well. The [provider comparisons](/compare/) and [current pricing](/pricing/) supply the product-specific inputs; this article's model supplies the cost categories.

The [managed runner selection guide](/blog/managed-github-actions-runners/) covers platform requirements, isolation, and a representative pilot alongside these cost categories.

## Three monthly scenarios

Each attempted workflow contains one five-minute job. The small workload has
1,100 attempts and 1,000 successful outcomes; the busy workloads have 44,000
attempts and 40,000 successes. Equal runtime and equivalent throughput across
providers are assumptions, not measured results.

The small fleet keeps one hypothetical instance running for 730 hours, with
91.7 active hours. The busy fleets use ten instances for 440 hours each, with
366.7 active hours per instance. The instance rate is illustrative, not a quote
for a named EC2 machine.

The GitHub-hosted examples assume a private workload with 2,000 included minutes
still available. Each scenario is a separate alternative, so those allowances
must not be added together. All scenarios value labor at $100 per hour, amortize
setup over twelve months, and allocate one operations hour to GitHub-hosted CI.

| Monthly model output | Small dedicated fleet | Busy fleet, established operations | Busy fleet, new operations |
|---|---:|---:|---:|
| Successful workflows | 1,000 | 40,000 | 40,000 |
| Self-hosted active-time share | 12.6% | 83.3% | 83.3% |
| Self-hosted compute | $73 | $440 | $440 |
| Self-hosted other infrastructure | $91 | $183 | $183 |
| Self-hosted recurring labor | $400 | $100 | $800 |
| Self-hosted setup allocation | $200 | $50 | $400 |
| Self-hosted total | $764 | $773 | $1,823 |
| GitHub-hosted total, including labor | $131 | $1,458 | $1,458 |
| Self-hosted cost per successful workflow | 76.40 cents | 1.93 cents | 4.56 cents |
| GitHub-hosted cost per successful workflow | 13.10 cents | 3.65 cents | 3.65 cents |

Both busy self-hosted cases have $623 in infrastructure costs. Established
operations add one hour of monthly work and six setup hours. New operations add
eight hours per month and 48 setup hours. Those assumptions produce totals of
$773 and $1,823 against the same $1,458 GitHub-hosted total.

That leaves $835 between self-hosted infrastructure and the GitHub-hosted total.
After the established case's $50 setup allocation, about **7.85 operations hours
per month at $100/hour** would exhaust the remaining headroom. These figures
show where the result changes; they are not staffing recommendations.

## Include the costs around compute

The examples charge a dedicated EKS control plane fully to CI: 730 hours produces
a $73 monthly line under the supplied standard-support rate. That charge
continues when workers scale to zero. It is included in the table's other
infrastructure row, not an additional charge to add afterward. Check
[EKS pricing](https://aws.amazon.com/eks/pricing/) for the support tier you use.

Also include disks, caches, artifacts, registries, logs, network transfer, NAT,
public addresses, monitoring and applicable platform fees. For shared services,
state how much CI is allocated. An unchanged shared bill may be excluded from an
incremental-cost comparison, but that choice should be explicit.

Engineering time covers image updates, access changes, capacity tuning, cluster
maintenance and incidents. Value recurring work separately from setup:

```text
monthly operations = hours per month * loaded hourly cost
monthly setup allocation = setup hours * loaded hourly cost / amortization months
```

Managed runners still require workflow maintenance and troubleshooting. Include
that work on both sides. Labor represents economic cost and may not increase
this month's payroll, so keep infrastructure-only and labor-inclusive totals
visible separately.

## Replace the assumptions with your workload

Extract the download and run it locally with Node.js:

```sh
node model.mjs scenarios.json
node --test model.test.mjs
```

No dependencies, credentials or cloud calls are required. Copy `scenarios.json`
and replace four groups of inputs:

1. Successful outcomes and the duration of every charged job attempt.
2. Instance lifetimes, split into active and idle wall time.
3. Storage, network, cluster and service expenses for the same period.
4. Setup effort, recurring operations hours and the amortization period.

Vary runtime, utilization, retries and operations effort separately. Faster
hardware can cost more per hour and less per workflow; an idle fleet can reverse
that advantage. Keep queue time and reliability beside the cost result.

The supplied totals exclude taxes, negotiated discounts, commitments, credits,
incident losses and the value of faster feedback. They demonstrate the accounting
method, not a cheapest provider or an equivalent security boundary.

## Self-hosting or 9apes?

Self-hosting can make sense when steady demand keeps machines busy and your
platform team can operate the fleet with modest additional effort. Your team
owns capacity planning, upgrades, idle infrastructure and incident response.

With 9apes, we manage the runner infrastructure. You pay for runner minutes
instead of maintaining a fleet between jobs, while your team continues to own
workflow code, dependencies and secrets. That reduces the infrastructure work
included in the self-hosted side of this model.

The table above uses GitHub-hosted pricing, not 9apes rates. To compare 9apes,
use the [current pricing](/pricing/), your remaining included usage, measured job
durations and workflow-maintenance effort. Start with one workflow using the
[9apes quickstart](/docs/quick-start/) and compare cost per successful outcome.
