An exact key miss with no restore keys means starting from nothing, which for a node_modules cache is the difference between four seconds and ninety.
- uses: actions/cache@v2
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
# exact key hits → restored, and not saved again
# exact key miss → the newest matching prefix is restored,
# and the new cache IS saved at the end
The restore key is a prefix match against the most recently created cache, so a lock file change starts from the previous install rather than from empty. Caches are immutable once written, which is why the key must contain the hash — reusing a fixed key means the first run of the week populates it and nothing ever updates it. The scoping rules are the other surprise: a cache written on a branch is visible to that branch and to the default branch, and not to sibling branches.