Plainwork

Plainwork / Minutemeter / Why GitHub Actions minutes run out, with the math

Why GitHub Actions minutes run out, with the math

On a private repository, GitHub Free includes 2,000 Actions minutes a month. Most people who run out did not run something huge; they met one of four multipliers they did not know were there. Here is each one with the arithmetic, so you can check your own workflows.

1. Every job rounds up to a whole minute

GitHub's runner pricing page says it "rounds the minutes and partial minutes each job uses up to the nearest whole minute" (source). A health check that takes 20 seconds bills 1 minute. Run on a schedule, that adds up quickly (a month averaged over a year, one billed minute per run):

ScheduleCronRuns a monthShare of 2,000 free minutes (standard Linux runner)
every 5 minutes*/5 * * * *8,760438%
every 10 minutes*/10 * * * *4,380219%
every 15 minutes*/15 * * * *2,920146%
every 30 minutes*/30 * * * *1,46073%
every hour0 * * * *73037%
once a day0 6 * * *302%

One developer described exactly this on dev.to in September 2026: the free-tier billing block "hit in May" and "hit again in late June" on a pipeline of daily jobs that were "individually cheap — 2–4 minutes per run — but daily crons multiply fast" (post).

2. A matrix multiplies, and each leg has its own price

A matrix of 3 operating systems and 3 Node versions is 9 jobs, not 1. At 5 minutes each that is 45 billed minutes for one run: 3 Linux jobs (3 x 5 min x $0.006), 3 Windows jobs (3 x 5 min x $0.010) and 3 macOS jobs (3 x 5 min x $0.062), which comes to $1.17 a run. The macOS third of the matrix is 79% of that cost.

3. The price per minute depends on the operating system

From GitHub's table (read 2026-10-12): Linux 2-core $0.006, Linux 1-core ubuntu-slim $0.002, Linux arm $0.005, Windows $0.010, macOS $0.062 per minute. macOS is about 10 times Linux. Larger runners are billed at their own rates even in public repositories.

4. No timeout means up to 360 minutes when something hangs

The default for timeout-minutes is 360 (workflow syntax). One hung job that is never cancelled bills: Linux $2.16, Windows $3.60, macOS $22.32. Setting a limit of about twice the normal run time caps that.

Two more that are easy to miss

  • Push and pull_request together. on: [push, pull_request] without a branch filter runs the workflow twice for a commit on a branch with an open pull request. Limit push to your default branch.
  • Superseded runs. Without concurrency and cancel-in-progress, an older run keeps going after you push again.

Public repositories, and the shared allowance

Standard GitHub-hosted runners are free in public repositories, and for GitHub Pages and Dependabot. For private repositories the included minutes (Free 2,000, Pro and Team 3,000, Enterprise Cloud 50,000) are shared by everything on the account, so several small repositories can add up to one large bill. Without a payment method on file, usage is blocked once the quota is used (billing docs).

Work it out for your own files

Paste your workflows into the free minutes calculator to get the numbers above for your jobs, with the line that causes each charge. The same engine is a free command line tool (a VS Code extension is coming soon); see Minutemeter.

More from the catalogue

Other small tools

See everything →