Skip to content
compiler.dev

How to Reduce Your GitHub Actions Bill

GitHub Actions bills are driven by a few simple rules, and most overspend comes from not knowing them. This guide explains how minutes are counted and lists the changes that cut the bill without slowing your team down.

How GitHub bills Actions

From GitHub's billing docs and runner pricing page:

  • Public repositories on standard runners are free. Private repositories get included minutes per month: 2,000 on Free, 3,000 on Pro and Team, 50,000 on Enterprise Cloud.
  • Each job's time is rounded up to the next whole minute. A 61 second job bills as 2 minutes.
  • Included minutes are consumed at a multiplier by OS: Windows uses 2 minutes per minute, macOS uses 10.
  • After the included minutes, you pay per minute: Linux 2-core $0.006, Windows 2-core $0.010, macOS 3-core (M1) $0.062.
  • Larger runners are never covered by included minutes. Linux 4-core is $0.012, 8-core $0.022, 16-core $0.042 per minute.
  • Artifact and cache storage count against separate quotas (the repository cache default is 10 GB).

Run your own numbers in the Actions cost calculator before choosing what to fix.

1. Find the expensive workflows

In your organization's billing page, open the Actions usage report and group by workflow and by runner SKU. Usually two or three workflows account for most of the spend, and macOS or large runners are far over their share. Fix those first.

2. Cancel redundant runs

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

On busy PRs this alone often removes 10 to 30 percent of minutes, since each push no longer leaves an older run going. Do not use cancel-in-progress for deploy workflows.

3. Skip runs that cannot fail

Use paths or paths-ignore so docs-only and config-only changes do not trigger heavy workflows. Draft PRs can skip expensive jobs:

jobs:
  e2e:
    if: github.event.pull_request.draft == false

4. Set timeouts

The default job timeout is 360 minutes. One hung job at 6 hours costs $2.16 on a 2-core Linux runner, and more on anything else. Set timeout-minutes per job to about twice normal duration.

5. Cut the matrix

A matrix of 3 OSes and 4 language versions is 12 jobs, and Windows and macOS minutes cost more. Test the full matrix on main or nightly, and a single combination on PRs. See matrix builds done right.

6. Be careful with macOS and Windows

A macOS minute costs about 10 times a Linux minute. Run Linux jobs on Linux, and only the steps that need a Mac on a Mac. For iOS, build and test on macOS but run linting, API tests and docs on Linux. See macOS runners for iOS CI.

7. Make jobs shorter, not just fewer

Billing is per minute, so a faster job is a cheaper job. Caching dependencies, Docker layers and build output cuts minutes directly. Start with how to speed up GitHub Actions and the caching guide.

Watch the rounding: a job that runs 20 seconds still bills a full minute. Merge tiny jobs (for example, separate lint and format jobs) so setup and rounding are paid once.

8. Right-size the runner

A bigger runner costs more per minute but can cost less per run. The break-even is simple: a 4-core runner at $0.012 beats 2-core at $0.006 if the job finishes in less than half the time. Measure with one workflow:

RunnerPer minuteRun timeCost per run
2-core Linux$0.00612 min$0.072
4-core Linux$0.0126 min$0.072
8-core Linux$0.0223.5 min, rounded to 4$0.088

These times are illustrative; use your own. Note how rounding and diminishing returns make the third row worse. Single-threaded steps will not shrink with more cores.

9. Trim artifacts and logs

Artifact storage is billed in GB-hours beyond the plan's included storage. Set short retention, and upload only what someone will use:

- uses: actions/upload-artifact@v4
  with:
    name: test-report
    path: reports/
    retention-days: 7

The default retention is 90 days unless your repository or organization sets a lower value. Compress large artifacts and skip uploading build output nobody downloads.

10. Consider other runners

For heavy use, running on your own machines or on a third-party runner provider can cost less per minute than GitHub's larger runners. The trade-offs are covered in self-hosted versus GitHub-hosted runners. Whatever you choose, compare cost per workflow run, not the price per minute.

Set budgets

In GitHub billing settings, create a budget for Actions with a stop-usage option or alerts. A runaway workflow, such as a cron job on a large matrix, will then hit a cap before it hits your credit card. Use the CI minutes forecaster to set the budget from expected usage, and read forecasting CI costs to plan for team growth.

FAQ

Are failed runs billed?

Yes. Any minutes a job runs are billed, whether it passes or fails, so fixing flaky failures and reruns saves money. See dealing with flaky tests.

Do waiting jobs cost money?

Queue time is not billed. A job waiting on an approval or a concurrency group is not running.

Do included minutes apply to larger runners?

No. Larger runners are always billed at the per-minute rate.

Is Windows worth avoiding?

Only run on Windows what must run there. A Windows 2-core minute is $0.010 versus $0.006 for Linux, and uses included minutes at double rate.

Check your own jobs

If you want a second opinion on a specific workflow, compiler.dev's comparison mode runs it on faster runners and shows run time and cost next to your GitHub-hosted run. Pricing for compiler.dev is published in the pricing section; compare cost per run, not just the per-minute rate.

Made by compiler.dev. Free tools · Pricing