You set up a small workflow to check your website every 5 minutes. It works well. Then, a few weeks later, GitHub tells you your free minutes are almost gone.
How did a tiny script use that much?
If you use GitHub Actions for small automations, this is worth understanding before it happens. The good news is that a few small changes can cut your usage a lot, and most of them take a couple of minutes.
Are GitHub Actions minutes actually free?
It depends on the type of repository.
- Public repositories: standard GitHub-hosted runners are free, with no minute cap.
- Private repositories: you get a monthly allowance based on your plan. The Free plan includes 2,000 minutes a month. After that, you pay per minute.
Two details catch people out:
-
Windows and macOS cost more. On private repos, a Windows minute counts as 2 and a macOS minute counts as 10. Stick to
ubuntu-latestunless you really need something else. - Every job is rounded up. A job that runs for 20 seconds is billed as a full minute.
(Allowances and prices change from time to time, so check GitHub's billing page for the current numbers.)
Why small workflows use more minutes than you'd expect
Here's the rounding in practice. Say your job takes 20 seconds, so it's billed as 1 minute each time it runs.
| Schedule | Runs per month | Minutes used per month |
|---|---|---|
| Every 5 minutes | 8,640 | 8,640 |
| Every 10 minutes | 4,320 | 4,320 |
| Every 15 minutes | 2,880 | 2,880 |
| Every 30 minutes | 1,440 | 1,440 |
| Every hour | 720 | 720 |
Based on a 30-day month. Each run is billed as 1 minute.
Now compare that to 2,000 free minutes. On a private repo, a check every 5, 10 or 15 minutes uses up the allowance before the month is over. Every 30 minutes fits, with some room left.
If your repo is public, none of this costs you anything. But public also means anyone can read your workflow files and code. Keep passwords and API keys in GitHub Secrets, never in the files themselves.
1. Run less often
This is the biggest saver, and it costs nothing.
Ask yourself how quickly you'd really need to know. For a personal project, finding out about downtime within 30 minutes is often fine. For a daily report, once a day is plenty.
Going from every 5 minutes to every 30 cuts your usage by 6 times.
While you're editing the schedule, avoid the top of the hour. GitHub can delay scheduled runs when it's busy, and the start of each hour is the busiest time.
on:
schedule:
- cron: '17,47 * * * *' # every 30 minutes, at :17 and :47
2. Set a timeout on every job
By default, a GitHub Actions job can run for up to 6 hours before GitHub stops it.
Picture a script that calls a website. The website hangs, your script waits, and the job sits there using minutes until the limit hits. On a private repo, one stuck run can use a big slice of your monthly allowance.
Add a timeout that matches what the job should take:
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 5
If your script normally takes 30 seconds, 5 minutes is plenty. If it takes longer than that, something is wrong and you want it stopped.
3. Cache what you keep downloading
If your workflow installs the same packages on every run, you're paying for that download time each time.
Caching saves those packages between runs. For Python, it's one extra line:
- uses: actions/setup-python@v5 # use the latest major version
with:
python-version: '3.12'
cache: pip
Treat the cache as a speed-up, not as storage. GitHub can remove old cache entries, so your workflow should still work when there's no cache.
4. Only run when something relevant changed
Some workflows run on every push, even when you only edited a README.
The paths filter tells GitHub to run the workflow only when certain files change:
on:
push:
paths:
- 'src/**'
- 'requirements.txt'
Now a typo fix in your docs doesn't start a test run.
5. Cancel runs you no longer need
Say you push three quick fixes in a row. Without any settings, GitHub runs the workflow for all three. Only the last one matters.
The concurrency setting cancels the older runs:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
This is great for workflows that run on pushes. Be careful with jobs where every run matters, like one that processes each order or sends a message. Cancelling those could skip work.
6. Keep the job count low
Each job is rounded up to a full minute and has its own setup time. Three small jobs that each take 15 seconds are billed as 3 minutes. One job with three steps might be billed as 1.
If the steps don't need to run on separate machines, put them in one job.
7. Check your usage before it becomes a problem
Look at the usage numbers in your GitHub account's billing settings. Once a month is enough. You'll see which workflow uses the most minutes, and it's usually one scheduled job that runs more often than it needs to.
It also helps to know what happens when you run out. On a private repo, your workflows can stop running or start costing money, depending on your billing settings. If a scheduled check simply stops, you may not notice right away, so it's worth setting up a way to be told when an automation breaks.
Quick answers
Is GitHub Actions free?
Yes for public repositories on standard runners. Private repositories get a monthly allowance, and the Free plan includes 2,000 minutes.
How can I check how many minutes I've used?
Open your account's billing settings and look at the Actions usage.
What uses the most minutes?
Usually a scheduled workflow that runs every few minutes, or a job that got stuck and ran until the timeout.
Do Windows and macOS runners use more minutes?
Yes, on private repositories. Windows counts double and macOS counts ten times.
When GitHub Actions stops being the cheapest option
For a few small checks and scripts, GitHub Actions is hard to beat. But if you need checks every minute, or a lot of frequent jobs on a private repo, the free allowance won't stretch that far.
At that point you can pay for extra minutes, run the job on a small server you already have, or use a tool built for that job. I compared the options for small teams in Zapier vs GitHub Actions.
The short version
Most free-minute problems come from three things: schedules that run too often, jobs that run longer than they should, and workflows that start when they don't need to.
Fix those, and a handful of small automations fits comfortably in the free allowance.
If you want to see this in a real project, my Python uptime monitor guide shows a check that runs on a schedule. You can find more practical automation guides on Procwire.
Top comments (0)