How to Cache Browser Binaries for Playwright and Cypress
E2E jobs often spend their first minute downloading browsers. Cache the binaries and that minute disappears.
Playwright and Cypress download large browser binaries on a cold runner. Cache them keyed on the tool version so they are only fetched when you upgrade.
Playwright
Cache the Playwright browsers directory keyed on the installed version.
.github/workflows/e2e.yml
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: pw-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- run: npx playwright install --with-depsCypress
Cypress caches its binary under ~/.cache/Cypress; cache it keyed on the Cypress version.
.github/workflows/e2e.yml
- uses: actions/cache@v4
with:
path: ~/.cache/Cypress
key: cypress-${{ hashFiles('package-lock.json') }}Key on the version
Tie the cache key to the lockfile or tool version so a browser upgrade re-downloads, but routine runs reuse the cached binaries.
Key takeaways
- Cache the browser binary directory, not just node_modules.
- Key on the tool/lockfile version to invalidate on upgrade.
- This removes the first-minute download from every E2E run.
Related guides
How to Cache Dependencies in GitHub Actions (Every Ecosystem)Cache dependencies in GitHub Actions with actions/cache - correct keys and paths for npm, yarn, pnpm, pip, Ma…
How to Reduce Cold Starts in CICut CI cold-start time: warm dependency caches, prebuilt images, and warm-pool runners that skip the provisio…
How to Warm Dependency Caches in CIPre-populate CI dependency caches from your default branch so pull-request runs always hit a warm cache inste…
How to Reduce Flaky-Test Reruns in CICut flaky-test reruns in CI: quarantine known flakes, fix shared state and timing, retry only what is genuine…