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

MechanismScopeNeedsUse it when
Caches view under the repository Actions tabOne entry at a time, picked from a listRepository write access in the browserYou are looking at the list already and want two or three entries gone
gh cache delete <key> or gh cache delete --allOne key, or every entry in the repositoryThe GitHub CLI, authenticated with write accessScripted 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 givenA token with actions: writeA 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 labelPrice per minuteCost of one cold rebuildCost 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: true

The 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 filterWhat it billsRate on hosted runnersRate on BYOC
storageGigabytes held per month$0.20 per GB-monthFree
operation-hitRestore and list calls$0.0001 per operationFree
operation-commitWrites$0.0001 per operationFree

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.

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.