GitHub Actions cache size limit 10GB: the cap and what it evicts
The GitHub Actions cache size limit 10GB default applies per repository, and crossing it fails nothing: GitHub deletes your least recently used entries to make room and the job stays green. The cost arrives later, as an install you thought you had eliminated, in a run whose YAML nobody has touched.

The 10 GB figure is the single most searched number in GitHub Actions caching and one of the least consequential on its own. At the default it behaves as a cap rather than a bill: GitHub evicts to make room instead of charging you, and no job fails. Raising the limit is what changes that, because any usage beyond 10 GB is billed to your account. What makes it worth a page is the failure mode: eviction is silent, so the repository that is quietly thrashing its cache looks exactly like the repository that is not.
This page is documentation-quoted rather than measured, for a reason it will name below, with one exception: the cache sizes it uses to make the arithmetic concrete are ones we measured on runners this week rather than guessed at.
What the limit actually says
GitHub's own wording, read on 20 September 2026, is worth quoting rather than paraphrasing, because the paraphrases circulating are wrong in three places. It is a default, so it can be raised. Raising it is not free, because storage above 10 GB is billed. And it is per repository, not per organization, not per branch and not per workflow.
Four sentences carry the whole rule, and the second is the one most summaries drop. "By default, the limit is 10 GB per repository, but this limit can be increased by enterprise owners, organization owners, or repository administrators." "Any usage beyond 10 GB is billed to your account." "Once a repository has reached its maximum cache storage, the cache eviction policy will create space by deleting the caches in order of last access date, from oldest to most recent." "GitHub will remove any cache entries that have not been accessed in over 7 days."
| Rule | What GitHub does | What you see |
|---|---|---|
| 10 GB per repository, by default | Enterprise owners, organization owners and repository administrators can raise it, on an account with a payment method on file that opts in through the cache settings | Nothing while you stay at the default, because GitHub evicts rather than charges. Past a raised limit, usage beyond 10 GB becomes a billed line |
| Eviction at the cap | Entries are deleted in order of last access date, oldest first, until the new entry fits | A cache that was there last week is not there this week, and no log line says why |
| Seven days without a read | The entry is removed regardless of how much room is left | A repository that is quiet over a holiday is cold on the first day back |
Why this page has no measurement of its own
We would rather show you a real listing filling up and evicting than quote a policy at you, and we cannot. Reading a repository's cache usage goes through the Actions cache API, and that API only answers a token issued to a GitHub-hosted job or a personal token with repository scope. Our timing harness runs jobs on Latchkey runners outside any GitHub workflow, so it has no such token, and we are not going to print a listing we did not produce.
So the commands below are the documented ones with their real fields, and the sizes in the arithmetic are measured. Everything else on this page comes from GitHub's documentation with the date we read it. That distinction is the whole point of publishing the numbers we do have.
See what you are actually using
Three ways in, and the first one is free. In the repository, open Actions and then Caches in the left sidebar under Management. The list shows how much disk space each cache is using, when it was created and when it was last used, and you can filter by branch or search with key: key-name. Deleting an entry from that page needs write access to the repository.
From a terminal, the GitHub CLI has a built-in gh cache command. The most useful invocation is not the default one: sort ascending by last access and you are looking at exactly the entries eviction will take first. The REST API behind it is a GET on actions/cache/usage for the repository total and on actions/caches for the entries, the latter accepting key, ref, sort and direction.
# total bytes this repository is holding
gh api repos/{owner}/{repo}/actions/cache/usage
# the entries eviction will take first
gh cache list --sort last_accessed_at --order asc --limit 100
# everything under one prefix, so you can see a matrix's whole footprint
gh cache list --key npm-Linux- --limit 100
# drop one entry, or every entry on one branch
gh cache delete npm-Linux-a91f4c2e7b
gh cache delete --all --ref refs/heads/stale-branch --succeed-on-no-cachesWhat a cache actually costs, in measured numbers
The abstract cap only becomes a decision when you know what your own entries weigh. These are directories we measured on Latchkey runners this week rather than figures from a blog post, each one the real size of the thing you would be caching.
Read the right column, not the left one. A single entry is small; a matrix multiplies it. Three Python versions times two operating systems is six entries of the pip cache, and each is a separate key. The repository that quietly outgrows 10 GB is almost never the one with a huge cache, it is the one with a wide matrix and a Docker layer cache in the same repository.
| What you would cache | Measured size | Times a 6-leg matrix |
|---|---|---|
| Docker layer cache, small two-stage Node image | 106 MB | 636 MB |
| A Python virtualenv, 26 pinned packages | 77 MB | 462 MB |
~/.m2/repository, one Spring Boot web dependency | 55 MB | 330 MB |
~/.gradle/caches, the same project | 29 MB | 174 MB |
~/.npm, a 414-package lockfile | 20 MB | 120 MB |
~/.cache/pip, the same 26 packages | 15 MB | 90 MB |
Split the caches so one cannot evict the others
Eviction is repository-wide and blind to what an entry is for. A Docker layer cache that rolls on every commit will happily take out the dependency cache your test job depends on, because the dependency cache is the one that was read less recently. The two are not competing on merit, they are competing on timestamp.
The fix is to stop the churning cache from being large, not to make the important one larger. Cap what the volatile entry holds, keep the stable entries keyed so they are read on every run and therefore stay recent, and move anything genuinely big to a store that is not the Actions cache. A registry is the usual answer for image layers, and it removes the largest row in the table above from the budget entirely.
# the layer cache, capped and scoped rather than unbounded
- uses: docker/build-push-action@v7
with:
cache-from: type=gha,scope=${{ github.workflow }}
cache-to: type=gha,scope=${{ github.workflow }},mode=min
# the dependency cache, read on every run so it never becomes the oldest entry
- uses: actions/cache@v6
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-Clean up on a schedule, not in a panic
Most repositories at the cap are holding entries for branches that were merged months ago. Pull request caches are written against the merge ref, so they can only be restored by re-runs of that pull request, and once it is closed they are pure occupancy. GitHub documents a workflow for exactly this, triggered when a pull request closes, which lists that branch's caches and deletes them.
Do the same for the long tail on a weekly schedule. The point is not to get under 10 GB once, it is to keep the entries you actually restore at the recent end of the list, because that is the only thing eviction looks at.
on:
pull_request:
types: [closed]
jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- run: |
gh cache list --ref refs/pull/${{ github.event.pull_request.number }}/merge \
--limit 100 --json id --jq '.[].id' \
| xargs -r -n1 gh cache delete
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}Frequently asked questions
Can I raise the 10 GB cache limit?
What are the workarounds when a repository keeps hitting the cache quota?
mode=min or push them to a registry instead, which removes the biggest entry from the budget. Delete pull request caches when the pull request closes, since they can only be restored by re-runs of that pull request anyway. And narrow your matrix, because each leg writes its own entry and a wide matrix is usually the real cause.Can I point the Actions cache at my own storage?
actions/cache itself; the request to allow it has been open on the repository since 2020 as "Alternative storage backend". What you can do is use a different mechanism for the large things: a container registry for image layers, and for self-hosted or third-party runners a cache backend that action supports. The keyed-archive model on this page still applies, the bytes just live somewhere else.What is the difference between the cache size limit and artifact storage?
Does the 7-day rule apply even when I am well under 10 GB?
Related guides
References
- GitHub Docs: caching dependencies, limits and eviction policy (verified 2026-09-20)
- GitHub Docs: managing caches, including the cleanup workflow (verified 2026-09-20)
- GitHub REST API: Actions cache usage and cache entries (verified 2026-09-20)
- GitHub CLI manual: gh cache list (verified 2026-09-20)
- actions/cache issue 6: the cache limit is too small (verified 2026-09-20)
- GitHub Actions documentation