DEV Community

Cover image for Solved: Pricing changes for GitHub Actions
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: Pricing changes for GitHub Actions

🚀 Executive Summary

TL;DR: GitHub now bills organizations for Actions triggered from forks of private repositories, leading to unexpected cost spikes. Solutions include immediately disabling fork workflows, setting spending limits, optimizing runner types, or implementing self-hosted runners for greater control.

🎯 Key Takeaways

  • GitHub now bills organizations for Actions initiated from forks of private repositories, a significant shift from previous assumptions.
  • An immediate, though blunt, solution to stop billing overruns is to disable fork pull request workflows at the GitHub Organization level.
  • Permanent cost control involves setting strict spending limits and optimizing workflow runner types (e.g., using ubuntu-22.04 instead of ubuntu-latest) to match job requirements.
  • For massive usage or specific needs, self-hosted runners offer ultimate cost control and performance customization but introduce significant maintenance and security responsibilities.

GitHub Actions pricing changes can lead to unexpected bills, especially from forked private repositories. This guide provides immediate, permanent, and advanced solutions from a senior engineer to control your CI/CD costs.

GitHub Actions is Costing You a Fortune. Let’s Fix That.

I still remember the Monday morning alert from finance. Our cloud bill had a spike that looked more like a mountain. After a frantic half-hour of digging, we found the culprit: a junior engineer had forked one of our legacy monolithic repos over the weekend to test a small change. They didn’t realize the fork inherited our entire suite of CI/CD workflows, which, due to a poorly configured cron trigger, ran every five minutes. For 48 hours straight. On ubuntu-latest-4-cores runners. We burned through our entire monthly GitHub Actions budget before most people had their first coffee. It was an expensive, painful lesson in just how easily these costs can spiral out of control if you aren’t paying attention.

So, What Changed? The Root of the Billing Pain

For a long time, the community operated under the assumption that Actions running on forks were “free,” especially in the context of open-source collaboration. The mental model was simple: the contributor uses their own Actions minutes. But recently, GitHub clarified and began enforcing a policy that hits organizations directly: for private repositories, your organization is now billed for Actions initiated from forks.

Think about that. Any user with read access can fork your private repo, push a commit to their fork, and trigger your workflows using your organization’s paid minutes. While there are some safeguards, it’s a significant shift that turns every fork into a potential drain on your budget. Combine this with the generous, but finite, pool of free minutes and the premium cost of larger runners, and you have a perfect recipe for a billing surprise.

Stopping the Bleed: Three Levels of Defense

When you’re facing a cost overrun, you need a plan. Here are the three approaches we use at TechResolve, from pulling the emergency brake to building a long-term, cost-effective CI/CD platform.

Solution 1: The Quick Fix (Triage Mode)

The first thing to do when the house is on fire is to put out the fire. The fastest way to stop the bleeding from forked repos is to disable them at the organization level. This is a blunt instrument, but it’s effective immediately.

How to do it:

  1. Navigate to your GitHub Organization’s Settings.
  2. In the left sidebar, click Actions, then General.
  3. Under “Fork pull request workflows from outside collaborators”, select Disable workflows.
  4. Scroll down to the “Fork pull request workflows” policy and select Disable for all repositories.
  5. Hit Save.

This stops the immediate problem. No workflows will run on forks of your private repos, period. Of course, this might break the workflow for your external contributors or even internal teams that use a fork-based model, but it gives you breathing room to implement a better, more permanent solution.

Warning: This is a sledgehammer approach. It stops the billing issue cold, but it also stops legitimate development workflows. Use this to stop an active billing incident, but don’t leave it this way forever if you rely on contributions from forks.

Solution 2: The Permanent Fix (The Right Way)

Once you’ve stopped the immediate bleeding, it’s time to set up proper guardrails. This involves setting strict spending limits and using cheaper runners where possible.

First, set a spending limit. Even a limit of $1 is infinitely better than an unlimited budget. This acts as a circuit breaker. If a rogue workflow goes wild, it will hit the cap and stop, preventing a four or five-figure bill. You’ll get a notification, and you can then decide whether to increase the limit or investigate the cause.

Second, let’s optimize the workflows themselves. Does your linter really need a 4-core machine? Can your unit tests run on a standard ubuntu-latest runner instead of a larger, more expensive one? Shaving a few cents off each run adds up to hundreds or thousands of dollars over a month across dozens of repos.

A simple workflow change looks like this. Instead of the default:

jobs:
  build:
    runs-on: ubuntu-latest # This can default to a more expensive machine
    steps:
      ...
Enter fullscreen mode Exit fullscreen mode

Be explicit about using the most cost-effective runner that can do the job:

jobs:
  build:
    # Use a more specific, and potentially cheaper, runner if it fits your needs.
    # Check GitHub's documentation for the latest runner labels and specs.
    runs-on: ubuntu-22.04 
    steps:
      ...
Enter fullscreen mode Exit fullscreen mode

This combination of a hard spending limit and right-sizing your runners is the most sustainable way to manage costs without resorting to drastic measures.

Solution 3: The ‘Nuclear’ Option (Self-Hosting)

If your Actions usage is massive, or you have specific compliance or hardware needs (like GPU access), the ultimate cost-control move is to use self-hosted runners. Instead of paying GitHub per minute, you’re just paying for the compute on your own infrastructure (AWS, Azure, GCP, or even on-prem servers like build-agent-k8s-pod-xyz).

This gives you total control over cost and environment. You can use cheap spot instances, autoscale your runners based on demand, and customize the environment with any software you need. However, it comes with a huge trade-off: you are now responsible for securing, maintaining, and patching these machines. Running code from a forked PR on your own infrastructure is a massive security risk if not handled properly. You need to treat these runners as ephemeral, single-use, and heavily firewalled.

Here’s a quick breakdown of the trade-offs:

Factor GitHub-Hosted Runners Self-Hosted Runners
Cost Pay-per-minute. Can be high and unpredictable. Pay for your own compute. Can be very low with optimization (e.g., spot instances).
Maintenance Zero. Managed entirely by GitHub. High. You are responsible for patching, scaling, and security.
Security Handled by GitHub. Isolated environments for each job. Your responsibility. High risk if running untrusted code from public forks without proper sandboxing.
Performance Limited to available GitHub machine types. Unlimited. You can use any machine size or type (e.g., GPU, ARM).

Moving to self-hosted runners is a major architectural decision, not just a quick fix. But for large organizations, the long-term cost savings can be immense. We use a hybrid model at TechResolve: critical production deployments use secure, hardened self-hosted runners, while general PR checks and linting run on the cheaper GitHub-hosted machines with a strict spending cap. It’s the best of both worlds.


Darian Vance

👉 Read the original article on TechResolve.blog


☕ Support my work

If this article helped you, you can buy me a coffee:

👉 https://buymeacoffee.com/darianvance

Top comments (0)