What we pay for.
GitHub bills every job that runs on its machines by the minute, rounded up per job. The organization gets 50,000 Linux minutes a month for free, worth $300 at the $0.006 rate we pay. Everything beyond that is the overage finance sees.
Two monorepos carry 94% of the usage. A single workflow in each, Backend CI in Collections and CI in Cloud, accounts for more than half of all billed minutes on its own.
Why it is this high.
The bill is volume times the cost of one run times the number of times we repeat that run. All three are high at the moment, and none of them is a mistake by any one person: they are the shape of a team shipping fast with a CI that was tuned for safety, not for price.
Volume
1,894 pull requests were opened in October across the five active repositories, about 90 per business day from 12 authors. Agent-assisted work from the owner's account produced 762 of them.
That same account is charged 76% of all minutes. Part of that is its own PRs; the rest is attribution: runs that happen after a merge, and the scheduled jobs, are billed to whoever merged or last touched the workflow, which is almost always the owner.
A heavy run for every push
A Cloud pull request bills about 30 minutes across 14 parallel jobs, including three race-test shards and a job that checks the Collections and Salesforce repositories against the new engine. It has no path gating, so a documentation change pays the same as an engine change.
A Collections push fans out into six workflows, each paying its own one-minute decide and gate jobs, plus a verdict workflow that fires once for every upstream workflow that finishes: 2,500 runs in October for a one-line status update.
Double work after merge
Cloud re-runs the full 30-minute CI on every push to main, 332 times in October, even though the same commit passed minutes earlier as a pull request.
Collections re-runs its 24-minute trusted lane on every push to develop, 564 times, and never cancels a run that a newer merge has already made obsolete. Merges arrive in bursts, so a large share of those runs test a commit that is no longer the head.
Attribution follows the GitHub actor, not the author of the change. Post-merge runs on main and develop, scheduled jobs and release runs land on the person who merged or dispatched them. Read the account table as "where the triggers come from", not as a per-person bill.
How we bring it down.
Step A is configuration only: six workflow files, no new infrastructure, and nothing that weakens what a pull request has to pass. Step B moves the pull-request lanes onto machines we rent, which GitHub does not meter. Savings are estimated at October volume.
Step A · Trim the hosted workflows
Stop paying twice for the same commit, run the expensive suites where they matter, and stop billing a full minute for jobs that only decide or report. Each item is a pull request in Cloud or Collections; the whole step fits in one week.
What stays exactly as it is
- Every check a PR has to pass. Gating moves the heavy suites to where the change touches them; it does not remove them.
- Release, deploy and migration rehearsal. Anything that touches production or staging secrets keeps running on GitHub-hosted machines.
- The relay model. Database credentials still never reach a developer machine.
Step B · Self-hosted runners for the PR lanes
After Step A we still use about 108,000 hosted minutes a month. Moving the untrusted pull-request lanes of Collections and Cloud to an ephemeral self-hosted pool leaves roughly 30,000 hosted minutes, inside the free allowance. Self-hosted minutes are not billed on Enterprise Cloud.
Sizing and cost
- Load. 80,000 minutes a month is about 1,300 runner-hours, concentrated in working hours.
- Pool. Two 16-vCPU cloud VMs running ephemeral runners, one job per runner, with Docker available for the database test containers. Budget $100–200 a month.
- Time. Two to three weeks, including a week running both lanes side by side.
Not counted above: each avoided pull request saves $0.50–0.70 at today's workflows. Batching or stacking agent-generated PRs before they hit CI would cut volume directly. That is a team workflow choice rather than an engineering change, so every estimate on this page assumes the current rate of about 1,900 PRs a month.
What it will cost.
Hosted minutes per month under each scenario, against the 50,000-minute allowance. November is forecast from the first ten days: about $55 of usage per weekday and $20 per weekend day.
What a sensible number is
For 12 active authors and 1,900 PRs a month at two pushes each, a well-gated CI bills 15–20 minutes per push, post-merge runs 5–10 minutes per merge, and scheduled work about 8,000 minutes. That is 80,000–100,000 hosted minutes a month, or $180–300 of overage, without self-hosting.
With the PR lanes self-hosted the hosted figure sits inside the allowance and the only recurring cost is the runner VMs.
When the top-up runs out
The allowance was used up on 7 November. From then on every minute is billed. At the current pace the $500 credit Kenneth added lasts until around 19–20 November.
Step A, once merged, takes effect on the next run, so the sooner it lands the more of November it saves. Landing it by 18 November keeps the month near $850 instead of $1,050.
Confidence
October figures are exact: they come from GitHub's own usage export. November to date comes from the billing API. Per-workflow savings are estimates from job timings sampled across the twelve most recent runs of each workflow and should be read as ±20%.
Every step is re-measured from the usage export after it ships, and this page is regenerated from that data.
What we need.
Three things: cover for November while the cuts roll out, a small standing budget for the runner machines from December, and a weekly number so nobody is surprised again.
November
Worst case if Step A slips to the end of the month. The realistic figure with Step A live from 18 November is about $850. Seat licences are unchanged and separate.
From December
Runner VMs at $100–200 plus a hosted buffer for release, deploy and anything that must stay on GitHub machines. Overage itself should be $0–100.
Monitoring
Minutes and overage per repository posted every Monday, with the pace against the allowance. The first alert fires when a week exceeds 25,000 hosted minutes.
How to read it.
Where each number comes from, how GitHub turns jobs into minutes, and what this report does not measure.
Data
- October. GitHub's organization usage export, 3,434 line items, one per day, repository, workflow and actor.
- November. The organization billing API, 1–10 November, same granularity without the workflow split.
- Runs and PRs. The Actions runs API for every hot workflow (event, outcome, wall time) and the search API for pull requests opened and merged per repository.
- Minutes per run. Job timings of the twelve most recent completed runs of each hot workflow, summed per run with GitHub's rounding.
How minutes are billed
Each job is billed separately and rounded up to a whole minute. A workflow with 14 parallel jobs that finishes in 6 minutes of wall time can bill 30 minutes. A job that only decides whether other jobs should run, or only reports that they did, bills a full minute every time.
Linux runners cost $0.006 a minute on this contract. The first 50,000 minutes each month are included; nothing on self-hosted runners is metered.
Not measured
- Per-job minutes for every run. Only sampled; the workflow totals are exact.
- Skipped-run share after gating. Estimated from the mix of files changed in October PRs, not replayed.
- Runner VM load at peak. Sized from monthly totals; the side-by-side week in Step B is where that gets measured.
- Seat licences. Listed for completeness; they do not move with any of this.