Invalidate or Clear GitHub Actions Cache

A need to invalidate GitHub actions cache can raise at any time and is especially useful when working on various build optimizations and tuning GitHub actions workflow itself.

Since there is no native way to do so, we have to rely on updating cache key and restore-keys fields. Fortunately, we can use environment or repository variables when defining them.

Later, by updating those variables (with workflow file update or through GitHub UI) we can invalidate all our caches. So that all subsequent workflow runs will recreate caches with updated cache key values.

Workflow Environment Variable

First, we define the workflow level cache_version environment variable, which can be changed later by updating the workflow file.

Once value changes, all cache keys are updated, and cache generation starts from scratch.

Old caches remain in a GitHub cloud storage and will be eventually removed based on the eviction policy.

name: PR Update

on:
  pull_request:
  workflow_dispatch:

env:
  cache_version: 1.1 # arbitrary property name

jobs:
  setup:
    runs-on: ubuntu-latest

    steps:
      - name: node_modules cache
        id: node-modules-cache
        uses: actions/cache@v4
        env:
          cache_name: node-modules-${{ env.cache_version }}
          hash: ${{ hashFiles('package-lock.json') }}
        with:
          path: node_modules
          key: ${{ runner.os }}-${{ env.cache_name }}-${{ env.hash }}
          restore-keys: ${{ runner.os }}-${{ env.cache_name }}-
yaml

We can also piggyback on an existent env variable, i.e. node_version, and change node minor version in order to invalidate the cache.

This is not the recommended approach, because behavior of node might change slightly with a minor version update, and it could lead to surprising and unwarranted bugs. Also, you might end up locking in a particular minor node version, instead of using the latest minor — i.e. node_version: 18.12 instead of node_version: 18.

On a flip side, you will invalidate all the cache values automatically on every node version bump.

Let’s combine the two:

name: PR Update

on:
  pull_request:
  workflow_dispatch:

env:
  cache_version: 1.1
  node_version: 18.12

jobs:
  setup:
    runs-on: ubuntu-latest

    steps:
      - name: node_modules cache
        id: node-modules-cache
        uses: actions/cache@v4
        env:
          prefix: ${{ runner.os }}-${{ env.node_version }}
          cache_name: node-modules-${{ env.cache_version }}
          hash: ${{ hashFiles('package-lock.json') }}
        with:
          path: node_modules
          key: ${{ env.prefix }}-${{ env.cache_name }}-${{ env.hash }}
          restore-keys: ${{ env.prefix }}-${{ env.cache_name }}-
yaml

This way we can invalidate cache by updating the cache_version environment variable. Bumping a node version causes the same effect.

Repository Variable

If you prefer to invalidate caches in GitHub UI without needing to update workflow files, you can use repository variables in your cache key expressions:

name: PR Update

on:
  pull_request:
  workflow_dispatch:

env:
  node_version: 18.12

jobs:
  setup:
    runs-on: ubuntu-latest

    steps:
      - name: node_modules cache
        id: node-modules-cache
        uses: actions/cache@v4
        env:
          prefix: ${{ runner.os }}-${{ env.node_version }}
          cache_name: node-modules-${{ vars.CACHE_VERSION }}
          hash: ${{ hashFiles('package-lock.json') }}
        with:
          path: node_modules
          key: ${{ env.prefix }}-${{ env.cache_name }}-${{ env.hash }}
          restore-keys: ${{ env.prefix }}-${{ env.cache_name }}-
yaml

This way CACHE_VERSION variable update will automatically invalidate the cache. All subsequent workflow runs will recreate relevant caches from scratch.

Conclusion

Even though there is no embedded mechanism to clear the GitHub actions cache, we can achieve it fairly easily with environment variables and updated workflow file or repository variable and GitHub UI.

Which, in a way, tells us that GitHub actions team came up with a succinct yet sufficient cache action “API”. They avoided adding extra functionality, when, in fact, workflow syntax (and GitHub UI) already provides generic (and, hence, familiar) means to do what we need.

Convenient? No! Efficient and reliable? Yes!

This Article Updates

  • Replaced repository secrets with variables and some minor edits. March 2023