What Does GitHub Actions Cache Storage Cost?

Cache for GitHub Actions costs $0.20 per GB-month of storage plus $0.0001 per write, restore, or list operation on WarpBuild hosted runners, free on BYOC.

Last verified:

Cache for GitHub Actions has two price components on WarpBuild hosted runners: $0.20 per GB-month of storage and $0.0001 per cache write, restore, or list operation. Both components are free on BYOC runners, where add-ons are included and the compute is billed by your own cloud account.

Answer

The cache bill separates what you keep from what you do. Storage is metered on the gigabytes held across the month. Operations are metered per call, whether the call writes an entry, restores one, or only checks whether one exists.

Line itemHosted runnersBYOC runners
Cache storage$0.20 per GB-monthFree
Cache write, restore, or list$0.0001 per operationFree

Rates come from the WarpBuild pricing page and the caching documentation, both checked on 2026-08-13.

Those two numbers make the arithmetic short. A 20 GB working set costs $4.00 for the month. A fleet that issues 50,000 restores and 6,000 writes in the same month adds $5.60. Nothing else attaches to the line, because pricing is purely usage based. There is no base subscription fee, no platform fee, and no seat fee, so cache spend never scales with the number of repositories or engineers on the account.

GitHub Actions Cache on GitHub-hosted runners carries no separate line on a GitHub invoice. It is constrained by a per-repository storage limit and an expiration policy instead, both configurable under organization Actions settings, as GitHub describes in its caching dependencies documentation, checked on 2026-08-13. WarpBuild takes the opposite trade: the cache has no size gate, and the gigabytes you choose to hold show up as a metered line.

Entries expire after 7 days of last use and can be deleted at any time from the console or from the action, so an abandoned branch stops billing about a week after its last job. Signup includes $10 free credits, which covers a full month of cache for most small fleets before anything reaches an invoice.

Detail

What the storage meter counts

The meter runs on gigabytes held over time, not on gigabytes written once. A 6 GB entry that lives for a full month bills $1.20. The same entry deleted after 10 days bills roughly $0.40. Cache size on WarpBuild has no quota to hit, which moves the ceiling from a hard limit to a number on the invoice, and makes retention the thing worth managing.

Three attributes decide how many copies of a working set you are holding. The cache is scoped to the key, the cache version, and the branch. Version is a hash of the compression tool and the list of cached paths, which is why a cache saved on warp-macos-14-arm64-6x cannot be restored on warp-ubuntu-latest-x64-4x. Each branch that saves an entry holds its own copy of it.

Branch scoping is the usual reason a cache bill grows faster than a repository does. A 2 GB dependency set on a single branch is $0.40 a month. The same 2 GB saved on 40 branches that stayed active through the month is 80 GB-month, or $16.00. Because entries expire 7 days after their last use, the steady state is roughly one copy per branch that ran a job inside a rolling seven day window, and long-lived release branches keep their copies alive indefinitely.

What the operation meter counts

Every cache call is $0.0001, so operations become material only at fleet scale. A workflow that restores three caches and writes one on each of 900 pull request runs a month issues 3,600 operations, or $0.36. An organization running 60,000 jobs a month with two cache steps each lands near 130,000 operations, or $13.00.

The report distinguishes the two kinds of call, which is what makes the number actionable: hits are recorded separately from commits, so a fleet paying mostly for commits is re-saving entries it should be restoring.

Splitting restore and save is the cheapest way to keep commits low, since the save step then runs only on a miss.

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

jobs:
  test:
    runs-on: warp-ubuntu-latest-x64-4x
    steps:
      - uses: actions/checkout@v4

      - name: Restore npm cache
        id: npm-cache
        uses: WarpBuilds/cache/restore@v1
        with:
          path: ~/.npm
          key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            npm-${{ runner.os }}-

      - run: npm ci

      - name: Save npm cache
        if: steps.npm-cache.outputs.cache-hit != 'true'
        uses: WarpBuilds/cache/save@v1
        with:
          path: ~/.npm
          key: ${{ steps.npm-cache.outputs.cache-primary-key }}

      - run: npm test

  integration:
    runs-on: warp-ubuntu-latest-arm64-8x
    steps:
      - uses: actions/checkout@v4

      - name: Restore build cache
        uses: WarpBuilds/cache/restore@v1
        with:
          path: .build-cache
          key: build-${{ hashFiles('**/lockfiles') }}
          fail-on-cache-miss: false

      - run: ./scripts/integration.sh

The key on the npm step changes only when package-lock.json changes, so a week of pull requests against a stable lockfile issues one restore per run and no writes. The restore-keys prefix keeps a partial match available after a dependency bump, which turns what would be a full miss into a hit plus one write. The lookup-only input is worth knowing about for the reverse case: it checks existence without downloading, which still bills one operation while skipping the transfer time.

A worked monthly model

Take an organization of 60 engineers running 6,000 workflow runs a month, five cache-using jobs per run, an average of 30 GB held across the month, and a 12 percent write rate on cache steps.

Line itemVolumeRateCost
Cache storage30 GB-month$0.20 per GB-month$6.00
Restore operations30,000$0.0001 each$3.00
Write operations3,600$0.0001 each$0.36
Total cache$9.36

Now put that next to the minutes it removes. Assume each hit skips 1.5 minutes of dependency installation. That is 45,000 minutes a month, which on warp-ubuntu-latest-x64-4x at $0.008 per minute is $360.00 of runner time that never gets billed. The same 45,000 minutes on the 4-core Linux larger runner from GitHub, listed at $0.012 per minute on the GitHub Actions per-minute rate list and checked on 2026-08-13, would be $540.00.

The failure mode runs the other way. A team that caches a 6 GB toolchain directory on 40 active branches holds 240 GB-month, or $48.00, and gets nothing extra for the duplication. Keying that entry to the toolchain version rather than the branch, and saving it from the default branch so feature branches restore it through restore-keys, collapses 40 copies into one and drops the line to $1.20.

Cache can be a small share of the total, depending on stored volume and job usage. Use the pricing page for current rates and model each line item separately.

Reading the real number instead of modelling it

The Cache tab of the Billing report carries the actual figures. Summary cards show total cost, storage cost, operations cost, and total entries for the selected period. A daily stacked bar chart breaks cost down by cache type, the table lists entries with their type and cost, and the filter set is storage, operation-hit, and operation-commit. Every view exports to CSV. The reports documentation covers the CI and Docker Builder tabs alongside it.

Three readings are worth taking each month. A storage cost climbing while entry count stays flat means entries are getting fatter, usually from a widened path list. An operation-commit share above a fifth of all operations means keys are churning, usually from a timestamp or a commit SHA in the key. A rising entry count with flat storage means branch sprawl, which the eviction window clears on its own once those branches go quiet. For splitting any of this across teams, the cost attribution guide covers the per job billing rows and the runner label and stack filters that make a chargeback key.

Where the cache line goes to zero

BYOC removes both components. Add-ons are included on BYOC runners, so storage and operations cost nothing and the underlying capacity is billed by your own cloud account.

Windows is the other case with no cache line, for a different reason. The caching documentation lists Windows runners as unsupported, so a cache step inside a job running on a warp-windows-latest-x64-4x label falls back to GitHub Actions Cache and produces no WarpBuild storage or operation charges. Caching is enabled by default on Linux runners.

Docker layer caching deserves its own decision. Proxying layers through the cache backend works and bills as ordinary storage and operations, and the documentation recommends remote Docker builders instead, where the persistent layer cache lives on the builder and bills per builder session.

When do GitHub Actions cache entries get evicted?

WarpBuild cache entries expire after 7 days of last use, so an entry that keeps getting restored keeps paying rent and an abandoned branch stops billing a week after its last job. Entries can also be deleted at any time from the console or with the delete-cache input on the cache action, which is the fast way to clear a large mistaken entry rather than waiting out the window. The eviction rules are covered in the caching documentation and in more depth in how long GitHub Actions caches last.

Can two workflows share a cache entry?

Yes, when they ask for the same key, the same cache version, and run on a branch that can see the entry. Version is a hash of the compression tool and the cached paths, so a cache saved by a macOS job cannot be restored by a Linux job even with an identical key. Entries saved on the default branch are the ones feature branches can restore, which is why storing shared toolchains there costs one copy instead of one per branch. The cache sharing answer works through the branch rules with examples.

Does WarpBuild cache work on Windows runners?

No. The caching documentation lists Windows runners as unsupported, so cache steps in a job running on a warp-windows-latest-x64-4x label fall back to GitHub Actions Cache and generate no WarpBuild storage or operation charges. Linux x64 and Linux ARM64 runners have the cache enabled by default, and macOS jobs can use it with the version caveat that a macOS entry restores only on macOS.

How do I see what my cache actually costs?

The Cache tab of the Billing report splits total cost into storage cost and operations cost, shows the entry count for the period, and filters by cache type: storage, operation-hit, and operation-commit. Every view exports to CSV, so a month of cache rows can be summed per type in a spreadsheet. Pair it with the size limit guide when storage is the growing half, and with the pricing page for the rest of the rate card.

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.