fix(dev): restore no-store for dev HTML responses to prevent bfcache hydration failures#94107
Closed
sleitor wants to merge 1 commit into
Closed
fix(dev): restore no-store for dev HTML responses to prevent bfcache hydration failures#94107sleitor wants to merge 1 commit into
sleitor wants to merge 1 commit into
Conversation
…hydration failures Fixes vercel#94036 Chrome's bfcache (back/forward cache) and disk cache can serve `no-cache` responses without revalidating on back/forward navigation. When the dev server has updated JS chunks (via HMR), this results in stale HTML with mismatched `__next_f.push()` chunks being restored, causing silent Turbopack hydration failures. PR vercel#91503 changed the dev HTML Cache-Control from `no-store` to `no-cache` to enable conditional revalidation (304 Not Modified). While correct for production, `no-cache` in dev allows bfcache to bypass revalidation entirely on back/forward, leading to stale page renders and broken hydration. Restore `no-store, must-revalidate` across all three dev HTML render paths (base-server, app-page template, pages-handler) so the browser never stores dev HTML in any cache, eliminating the stale-chunk issue. Update tests to expect `no-store, must-revalidate` accordingly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Restores
no-store, must-revalidateas the dev serverCache-Controlheader value for HTML document responses, reverting the behavioral change introduced in #91503 (which hard-codedno-cache, must-revalidate).Fixes #94036
Why?
Chrome's bfcache (back/forward cache) and disk cache can serve
no-cacheresponses without revalidating on back/forward navigation. This is a known browser behavior: back/forward navigations are treated differently from regular fetches, andno-cachedoes not reliably force revalidation in that path.In practice this means:
no-cache, must-revalidate__next_f.push()chunks reference build IDs/URLs from a previous buildHow?
Change
'no-cache, must-revalidate'→'no-store, must-revalidate'in the three dev HTML render paths:packages/next/src/server/base-server.ts(main render path)packages/next/src/build/templates/app-page.ts(app router)packages/next/src/server/route-modules/pages/pages-handler.ts(pages router)no-storeprevents the browser from storing the HTML in any cache (including bfcache), so back/forward navigation always results in a fresh request to the dev server. This eliminates the stale-chunk hydration failure.Note: The static asset path (
/_next/static/) is unaffected — it correctly usespublic, max-age=31536000, immutablein prod andno-cache, must-revalidatein dev, since JS chunks are fingerprinted by content hash and stale-chunk issues don't apply there.Update all tests that previously expected
no-cache, must-revalidatein dev mode.