Use deterministic, content-derived cache keys and ensure every producer/consumer of that cache computes the key identically.
Apply these rules when adding or modifying CI caching (especially GitHub Actions): 1) Key from real content inputs
2) Keep warm and restore in lockstep
main, the restore step must use the exact same key computation (including the exact strings and argument formatting) or you will get misses.${{ }}) are not the same as shell substitution ($(...)). If key-args is interpolated into a run: script, the shell will evaluate $(...), so the string must match what the warming workflow uses.3) Follow repo cache action pinning
actions/cache/restore + actions/cache/save pinning pattern already used in the repo to prevent behavior drift. If you want to upgrade pins, do it as a coordinated change.Example pattern (deterministic key + shared restore args)
- name: Restore browsers cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: .build/ms-playwright
key: "playwright-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.prepare.outputs.version }}-${{ steps.prepare.outputs.browsers }}"
# Where steps.prepare computes:
# - version from the pinned lockfile
# - browsers from the install args
Checklist for PRs