Cutting GitHub Actions Costs Without Rewrites

Cut GitHub Actions spend by right-sizing runners, ending re-run waste, and fixing cache misses. WarpBuild Linux runners start at $0.004 per minute.

Last verified:

Most teams reduce GitHub Actions costs with three moves: right-size each job's runner, stop paying for wasted minutes from re-runs and cold caches, and put the remaining minutes on a lower per-minute rate. WarpBuild covers the rate move with a one-line label change: its Linux x64 runners start at $0.004 per minute, against the $0.006 GitHub lists for a standard 2 vCPU Linux runner on its minute-multipliers reference (checked on 2026-08-13).

None of the fixes in this guide require rewriting workflows. The work ranges from a one-line edit in runs-on to an afternoon of reading billing reports, and every change shows up in the next billing cycle, where it can be verified or reverted.

Diagnosis

GitHub Actions spend rarely spreads evenly across an account. A few jobs usually generate most of the bill, and the waste concentrates in five patterns. GitHub's usage report, downloadable from the billing settings, shows minutes by SKU (standard Linux, Windows, macOS, and each larger runner tier), which is enough to see the shape of the spend before any per-job tooling gets involved. Read your last month against this list before changing anything.

Minutes on oversized runners. A runner size gets picked once, when the workflow is first written, and stays fixed while the workload changes underneath it. The result is a test job on an 8 vCPU machine that peaks at 30 percent CPU, paying the 8 vCPU rate for work that fits a smaller size. The reverse also costs money: an under-provisioned job swaps or thrashes and stretches its wall clock. Sizing arithmetic for GitHub's larger runner tiers gets full coverage in what GitHub Actions larger runners cost.

macOS minutes. macOS runners bill at a per-minute rate well above standard Linux, so a modest iOS pipeline can outbill a much larger Linux fleet. If macOS is a visible slice of your usage report, the per-minute arithmetic against GitHub's list price gets its own treatment in what macOS runners cost on GitHub Actions.

Idle time inside jobs. Billed minutes track wall clock, and wall clock includes waiting. A job that spends three of its ten minutes waiting for a service container health check, polling an external deploy, or sitting in a fixed sleep bills those three minutes at the same rate as the compute it actually used. Look for steps whose duration dwarfs their log output; those are the waits.

Re-run storms. Flaky tests convert into whole-workflow re-runs. Assume a 20-minute workflow and a suite that forces a re-run on 15 percent of pushes: the workflow's billed minutes rise by that same share, and the increase hides inside normal-looking usage because each re-run is a legitimate run. Stacked pushes compound it when every commit to a pull request runs the full suite even after a newer commit has made the older run irrelevant.

Cache misses forcing full rebuilds. A dependency install that restores warm in under a minute can take several minutes cold. When the cache key churns on every run, or the entry gets evicted between runs, every job pays the cold path, every day, in billed minutes. The same misses slow the build down, which is why this list overlaps with how to speed up GitHub Actions builds.

Fix

Work the list in a fixed order: measure first, then move the rate, then remove the waste. Measurement comes first because every later step needs a number to verify against.

Measure with the Reports and Observability surfaces

The Reports page breaks WarpBuild billing down to the individual job. The CI Billing tab lists each job execution with its repository, runner label, execution time, billed time, and cost, and filters by repository, runner label, stack, and job name. Sort by cost, export the CSV, and the top rows are the worklist. The same page shows the daily cost chart grouped by repository or runner label, which is the fastest way to see which fleet a spend spike came from.

The Jobs section aggregates every combination of repository, workflow, and job name over the selected period: run count, success rate, duration at P75 and P90, queue time at P75 and P90, and peak CPU and memory at P75 and P90. The CPU and memory columns need observability enabled, and metrics only collect for jobs longer than about one minute.

The Observability page turns those metrics into right-sizing recommendations. It aggregates from repository down to workflow, job, and instance type, then flags instances sustaining 80 percent or more CPU, memory, filesystem, or disk throughput as under-provisioned, and low-utilization instances as over-provisioned. That list is the right-sizing worklist: move over-provisioned jobs down one size, under-provisioned jobs up one, and re-check the same view a week later.

Move the per-minute rate

Each size is a runs-on label documented in the cloud runners catalog, and the images carry the same tooling as GitHub-hosted runners, so the change is the label itself. Pricing is purely usage based. There is no base subscription fee, no platform fee, and no seat fee. The pricing page lists the per-minute rate for every size, and signup includes $10 free credits, which is enough to run the cost model below against your own workload before committing.

If a build compiles and tests cleanly on ARM64, the ARM64 labels carry lower rates again: warp-ubuntu-latest-arm64-2x bills $0.003 per minute, and the ARM64 sizes run up to 32 vCPU at $0.048 per minute.

A shorter job bills fewer minutes at any rate.

Cut re-run and idle waste

Add a concurrency group with cancel-in-progress to every push-triggered workflow, so a new commit cancels the superseded run instead of letting it bill to completion. The YAML is in the Configuration section below.

Then rank workflows by the success rate column in the Jobs report and fix the flakiest suites first. Every failed run that needs a manual re-run bills its full duration twice. For idle time, the per-job CPU and memory percentiles show which jobs spend their minutes waiting rather than computing; replace fixed sleeps with condition polling, and move long external waits out of billed jobs entirely.

Keep caches warm

WarpBuild's cache is available on Linux-based runners and enabled by default, and the caching docs cover key design and the drop-in cache action. A stable key plus a warm cache removes the cold-install path from routine runs, which cuts both the bill and the wait. Eviction behavior and key churn get deeper coverage in the speed guide linked above.

One cost source sits outside this guide: egress charges from deploy-heavy workflows, covered in GitHub Actions egress costs and, for the enterprise tier, zero egress.

Configuration

The minimum change is one line in each job:

 jobs:
   test:
-    runs-on: ubuntu-latest
+    runs-on: warp-ubuntu-latest-x64-4x

Pick the size from measurement rather than habit. The Linux x64 sizes, from the cloud runners catalog:

LabelvCPUMemoryStoragePrice
warp-ubuntu-latest-x64-2x28GB150GB SSD$0.004/minute
warp-ubuntu-latest-x64-4x416GB150GB SSD$0.008/minute
warp-ubuntu-latest-x64-8x832GB150GB SSD$0.016/minute
warp-ubuntu-latest-x64-16x1664GB150GB SSD$0.032/minute
warp-ubuntu-latest-x64-32x32128GB150GB SSD$0.064/minute

A complete workflow with the cost controls from the Fix section applied:

name: ci
on:
  pull_request:
  push:
    branches: [main]

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

jobs:
  test:
    runs-on: warp-ubuntu-latest-x64-4x
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm test

The concurrency block cancels the older run when a newer commit lands on the same ref, which removes the stacked-push waste named in the Diagnosis section. The label change moves the job onto the measured size at the WarpBuild rate. Nothing else in the file changes, and rolling back means restoring the previous label.

Cost or Time Model

The model uses GitHub's public list prices from its minute-multipliers reference, checked on 2026-08-13, against WarpBuild rates at the same vCPU counts. Assumptions:

  • 6,000 standard jobs per month averaging 8 billed minutes each, currently on GitHub-hosted 2 vCPU Linux runners at a $0.006 per minute list price
  • 1,000 heavier jobs per month averaging 12 billed minutes each, currently on GitHub-hosted 8 vCPU Linux larger runners at a $0.022 per minute list price
  • Included minutes are ignored: at this volume a private repository exhausts the Free plan's 2,000 or the Team plan's 3,000 included standard-runner minutes within days, and GitHub's larger runners never draw from included minutes

The current monthly bill:

WorkloadMinutes per monthRateCost
6,000 jobs at 8 minutes, 2 vCPU48,000$0.006$288.00
1,000 jobs at 12 minutes, 8 vCPU12,000$0.022$264.00
Total60,000$552.00

The same jobs on WarpBuild labels at the same sizes:

WorkloadMinutes per monthLabelRateCost
6,000 jobs at 8 minutes48,000warp-ubuntu-latest-x64-2x$0.004$192.00
1,000 jobs at 12 minutes12,000warp-ubuntu-latest-x64-8x$0.016$192.00
Total60,000$384.00

The like-for-like move takes the monthly bill from $552.00 to $384.00, a difference of $168.00 per month or $2,016 per year, before any right-sizing.

Now add the measurement step. Suppose the Observability recommendations show the heavier job peaking at 35 percent CPU and 40 percent memory on 8 vCPU. Moving it to warp-ubuntu-latest-x64-4x at $0.008 per minute cuts that line from $192.00 to $96.00 and the monthly total to $288.00, provided the duration percentiles hold after the change. That proviso is the discipline of right-sizing: billed minutes track wall clock, so a downsize that stretches P90 duration gives back part of what the rate change earned. Re-check the Jobs report a week after each change and keep only the sizes that hold their duration.

Cache fixes stack on top. If warm caches cut the standard job's average from 8 billed minutes to 6, that line drops from 48,000 minutes to 36,000, and its cost from $192.00 to $144.00, taking the monthly total to $240.00.

Against the original $552.00, the measured end state runs $240.00 to $288.00 per month depending on how far the cache work goes, a difference of $264.00 to $312.00 per month, or $3,168 to $3,744 per year. The inputs were one label edit per job, one concurrency block, and an afternoon of reading reports.

That result belongs to the inputs in this model, not every fleet. Substitute your measured durations and use the pricing page for current per-size rates.

FAQ

Do WarpBuild runners require workflow changes beyond the runs-on label?

No. The runner images carry the same tooling as GitHub-hosted runners, so swapping runs-on to a warp- label is the whole migration for most jobs.

How does WarpBuild pricing work?

Pricing is purely usage based. There is no base subscription fee, no platform fee, and no seat fee. Runners bill per minute, and signup includes $10 free credits.

Can a smaller runner raise my bill by running longer?

Yes. Billed minutes track wall clock, so check the Jobs report after each change. If duration P90 stretches enough to offset the lower rate, move back up a size.

Are there concurrency caps that force a plan upgrade?

Run as many jobs as your workflows need. Generally available Linux and Windows runners do not have plan-level concurrency caps. High concurrency on macOS runners goes through [email protected].

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.