How Do I Clear a GitHub Actions Cache?
Change the cache key to walk away from a stale entry, and delete entries only when the stored bytes are wrong. The key bump, the CLI, the API, and the cost.
Change the cache key: entries are immutable, so a new key addresses a new entry and the next run starts clean from one edit to the workflow file, with no API call and no token carrying write access. Delete entries through the repository Caches view, gh cache delete, or the REST API only when the stored bytes themselves are the problem rather than merely out of date.
Answer
Two different problems get described with the same sentence, and they take opposite fixes.
A stale entry holds a tree you no longer want restored: last week's dependencies, an old compiler output directory, a build that predates a toolchain bump. Nothing about the stored bytes is dangerous. The workflow is simply asking for them by name. Change the name and the problem is over on the next run.
A poisoned entry holds bytes that must not be handed to another job: a credential file that a login step wrote into a cached directory, an archive that fails to unpack and breaks every restore, binaries built for the wrong architecture. Here the entry has to go, and the key change alone leaves it sitting in the store until it expires.
The version prefix, for invalidating a family in one edit
Bumping the lockfile hash is not enough on its own, because restore-keys performs a prefix match and will still hand the job the previous tree. Put a version segment at the front of the key and at the front of every rung, and one edit cuts the whole ladder:
- name: Cache npm downloads
uses: WarpBuilds/cache@v1
with:
path: ~/.npm
key: v3-${{ runner.os }}-${{ runner.arch }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
v3-${{ runner.os }}-${{ runner.arch }}-npm-Change both v3 strings to v4 and every key in the family stops matching stored entries at once. The next run misses, installs cold, and writes a v4 entry. The v3 entries stay until they age out, restored by nothing, which is the behavior you want while a branch that has not merged your edit is still running the old workflow. WarpBuilds/cache@v1 takes the same path, key, and restore-keys inputs as actions/cache@v4 and is a drop-in replacement for it (WarpBuild caching documentation).
The three ways to delete
| Mechanism | Scope | Needs | Use it when |
|---|---|---|---|
| Caches view under the repository Actions tab | One entry at a time, picked from a list | Repository write access in the browser | You are looking at the list already and want two or three entries gone |
gh cache delete <key> or gh cache delete --all | One key, or every entry in the repository | The GitHub CLI, authenticated with write access | Scripted cleanup, or clearing a repository before a fresh baseline |
DELETE /repos/{owner}/{repo}/actions/caches?key=<key>&ref=<ref> | Every entry matching that key, narrowed to one ref when ref is given | A token with actions: write | A workflow step, or removal that has to be auditable |
The REST surface also exposes DELETE /repos/{owner}/{repo}/actions/caches/{cache_id} for a single entry by id, and GET /repos/{owner}/{repo}/actions/cache/usage for the active entry count and total size in bytes (GitHub Actions cache REST reference, checked on 2026-08-13). gh cache list --sort last_accessed_at is the fastest way to see which entries are candidates before anything is removed.
Detail
What deletion costs the next run
The bill for deleting an entry is one cold run per branch that was restoring it. Take an npm download cache of about 0.8 GB where npm ci takes 4 minutes from empty and 30 seconds from a warm restore, which is 3.5 extra minutes on the first run after the delete. Substitute your own two numbers from the job log; the rates are fixed.
| Runner label | Price per minute | Cost of one cold rebuild | Cost across 6 active branches |
|---|---|---|---|
warp-ubuntu-latest-x64-2x | $0.004 | $0.014 | $0.084 |
warp-ubuntu-latest-x64-4x | $0.008 | $0.028 | $0.168 |
warp-ubuntu-latest-x64-8x | $0.016 | $0.056 | $0.336 |
warp-ubuntu-latest-x64-16x | $0.032 | $0.112 | $0.672 |
Per-minute rates from the pricing page, checked on 2026-08-13. Each cold run also writes one new entry at $0.0001 per cache operation, and storage returns to its previous level once the tree is rewritten, so the money is rounding error. The number that matters is the other column: 3.5 minutes added to whichever pull request happens to run next, multiplied by every branch that --all touched. On a repository with six active branches that is 21 minutes of pipeline time paid back over the following hours. Deleting one key on one branch is cheap. Deleting everything on a Friday afternoon is a decision the whole team feels on Monday.
That asymmetry is the reason the key bump is the default move. It costs exactly the same cold run, but it costs it once, on your schedule, on the branch carrying the edit.
Clearing entries on WarpBuild cache
The WarpBuild cache serves every one of those except Windows, where workflows keep actions/cache@v4. Entries have their own removal path. The delete-cache input removes the entry and skips both restore and save for that step:
- name: Drop the poisoned entry
uses: WarpBuilds/cache@v1
with:
path: ~/.npm
key: v3-${{ runner.os }}-${{ runner.arch }}-npm-${{ hashFiles('**/package-lock.json') }}
delete-cache: trueThe same removal is available from the WarpBuild console at any time. Left alone, an entry expires 7 days after its last use (WarpBuild caching documentation), which is a sliding window: an entry restored every weekday never reaches it, and an entry written once and never read again collects itself. There is no repository size ceiling on the WarpBuild store, so nothing is evicted to make room for a newer write, and clearing entries to reclaim space stops being a maintenance task. The GitHub Actions cache size limit, explained covers the ceiling that makes it one.
One behavior surprises people mid-cleanup. A key is only half of an entry's identity: the cache action derives a version from the path list and the compression tool on the machine, and that version is a field on every entry in the cache list API (GitHub Actions cache REST reference, checked on 2026-08-13), so two jobs with identical key text and different paths address different entries. Delete by key and the sibling entry under the other version survives, which reads as a delete that did nothing. Entries are also scoped per branch, so removing the copy your pull request restores leaves the default branch copy that every other branch falls back to.
Seeing cache usage as its own line in the billing report
Before deleting anything, it is worth knowing what the store actually costs. The Reports page splits billing into CI, Docker Builder, and Cache tabs. The Cache tab carries a daily chart broken down by cache type, summary cards for total cost, storage cost, operations cost, and total entries, a per-entry table, and CSV export of every row matching the current filters.
| Cache type filter | What it bills | Rate on hosted runners | Rate on BYOC |
|---|---|---|---|
storage | Gigabytes held per month | $0.20 per GB-month | Free |
operation-hit | Restore and list calls | $0.0001 per operation | Free |
operation-commit | Writes | $0.0001 per operation | Free |
Rates from the WarpBuild caching documentation, checked on 2026-08-13. Reading the storage card before and after a cleanup is how you find out whether the entries you removed were the expensive ones, and the CI tab prices the cold runs the cleanup caused, per job and per runner label.
The guide to persistent caches on GitHub Actions covers the cases where the answer is a different mechanism instead of a cleaner cache.
Related Questions
Should I delete a cache entry or change the key?
Change the key in almost every case. Cache entries are immutable, so a new key addresses a new entry and the next run starts clean without an API call or a token with write access. Delete entries when the stored bytes themselves are the problem, such as a credential written into the archive or a tree that fails to unpack, and when you need space back under the repository cache cap right now. How to write a good cache key in GitHub Actions covers the shape that makes a bump safe.
How do I delete every cache in a repository at once?
Run gh cache delete --all, which removes every entry the repository holds across all branches. Add --succeed-on-no-caches so the command exits zero on a repository that already has none, which matters when the call sits inside a workflow. Deleting everything means every active branch pays one cold run before its entry is rewritten, priced in the table above at the per-minute rate on the pricing page.
Why did my cache come back after I deleted it?
Because the next run computed the same key and the save step wrote a fresh entry under it. Deletion removes stored bytes and changes nothing about what the workflow asks for. When the goal is that the old contents never return, bump a version prefix in the key and in every restore-keys rung in the same edit, then delete the old entries if the bytes were unsafe to keep. Cache eviction separates the four ways an entry disappears, only one of which you control from the workflow file.
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.