How to cut your GitHub Actions costs
UPDATED 2026-11-06
CI is billed by the minute, and agents push all day. So the same price produces a much bigger bill than it did when only people pushed code. These fixes go from cheapest to most work, and the first three need no hardware. The dollar figures are mine, from six days of usage at list price.
If your repo is public, you may already be done: standard GitHub-hosted runners are free for public repos.
Find the expensive row
Your billing page shows what you’ve used. To see it per job, run the report. It only reads your job history from GitHub and saves it to a local file. It needs Node 22.18 or newer, plus GITHUB_TOKEN or a gh login.
git clone https://github.com/Kloudy-Sky/runnerbox
cd runnerbox && pnpm install
pnpm runnerbox report --repo you/your-app
Here’s part of mine, trimmed to fit:
JOB RUNNER RAN P50 TOTAL
device-e2e (session) blacksmith-4vcpu-ubuntu-2404 285 8m 27s 2340m 23s
device-e2e (media) blacksmith-4vcpu-ubuntu-2404 284 6m 06s 1753m 13s
mac-x64 / mac x64 blacksmith-6vcpu-macos-15 149 6m 29s 873m 51s
mac-arm64 / mac arm64 blacksmith-6vcpu-macos-15 150 5m 27s 745m 23s
The report shows minutes, not dollars, so multiply by your runner’s price. That’s the trick: the mac rows look small here, and they were 57% of my bill.
Build desktop apps on releases
Most of my $152 in Mac and Windows builds went here. Nobody needs a signed desktop build for every push from an agent.
# Before
on: push
# After
on:
release:
types: [published]
Do the same for anything slow that doesn’t have to block a pull request. You can also run end-to-end suites only when a PR is ready, or limit a workflow to the files that affect it:
on:
pull_request:
paths:
- "apps/desktop/**"
Batch agent pushes
$22 of my usage went to jobs that were cancelled anyway. Agents push in bursts, and each push starts a full run. Add a line like this to your agent instructions:
Run checks locally. Push when the work is ready for review, not after every change.
Then stop paying for runs a newer push has already replaced:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
That setting leaves your main branch alone, so a deploy doesn’t get cancelled halfway through.
Set a budget before you need one
Check your limits for each service you use. GitHub stopped my CI when my budget ran out, while usage on another runner service kept billing past its free minutes. Not needing a card didn’t mean there was no bill.
Move Linux jobs to a machine you own
This was up to $85 of my bill, and it’s the most work. GitHub doesn’t charge for self-hosted runners today. It announced a $0.002 per minute fee and postponed it, so that could change. Read how to self-host a runner first, including when not to.
What runners cost
Checked November 6, 2026. Prices change, so follow the links before you decide.
| Service | Linux, 2 core | Included each month |
|---|---|---|
| GitHub hosted | $0.006/min | $12 on Free, $18 on Pro or Team |
| Blacksmith | $0.004/min | 3,000 minutes |
| BuildPulse | $0.004/min | 3,000 minutes |
| Your own machine | $0, plus power | Private repos only, unless you have to |
Per-minute price isn’t the whole story. Blacksmith charges less per minute than GitHub, and it’s still where my bill came from, because the bill is price times volume. macOS is the expensive multiplier everywhere: GitHub counted my macOS minutes at 10x.