nextjs - 💡(How to fix) Fix `next dev` 16.1+: back/forward navigation in Chrome leaves page un-hydrated due to Cache-Control change to `no-cache`

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

  • The disk-cached HTML carries __next_f.push(...) chunks tied to a specific dev-server session/build. When Turbopack's RSC bootstrap tries to consume this stale payload, hydration silently no-ops with no error surfaced.

Fix Action

Fix / Workaround

  • Tested on Chrome (incognito + with extensions disabled — same result, rules out extensions).
  • Production build (next build && next start) is unaffected.
  • A workaround for app-level fix while waiting for upstream:
    // app/layout.tsx — dev only
    if (process.env.NODE_ENV === "development") {
      // inline script in <head>
      // window.addEventListener('pageshow', e => {
      //   if (e.persisted) return;
      //   const nav = performance.getEntriesByType('navigation')[0];
      //   if (nav?.type === 'back_forward') location.reload();
      // });
    }
  • Setting Cache-Control: no-store from next.config.ts headers() or middleware does not override the dev-server-injected header — Next.js dev rewrites it on the response.
  • Bisected by version: 16.0.9 ✅ unaffected, 16.2.3 ❌ affected. (The transition aligns with PR #91503 merging into 16.1.)

Code Example

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:26 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T8132
  Available memory (MB): 32768
  Available CPU cores: 10
Binaries:
  Node: 24.13.0
  npm: 11.6.2
  Yarn: N/A
  pnpm: 10.28.2
Relevant Packages:
  next: 16.2.3 // There is a newer version (16.2.6) available, upgrade recommended! 
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/broBinChen/next-1623-bfnav-disk-cache-repo

To Reproduce

  1. use the linked repro
  2. pnpm dev and open http://localhost:3000/ in Chrome (verified on Chrome 138, macOS).
  3. Disable Network cache.
  4. Wait for the page to render hydrated ✅.
  5. In the URL bar, navigate away to any external site (e.g. https://example.com/).
  6. Click the browser Back button.

Current vs. Expected behavior

Current behavior (16.1+ / 16.2.3 verified):

  • After step 6, the page renders the SSR placeholder (SSR placeholder ⏳) and never updates.
  • No console errors, no unhandledrejection, no failed network requests.
  • DevTools → Network: the localhost document is served 200 (from disk cache) with Cache-Control: no-cache, must-revalidate. All JS chunks are also (from disk cache).
  • React never hydrates. useEffect never fires. Inline <script> tags in <head> do run (so the document executed scripts), but the Turbopack RSC bootstrap leaves the tree un-mounted.
  • A real-world consequence in our app: a full-screen loading placeholder rendered by SSR remains visible indefinitely; users have to manually refresh.

Expected behavior (matches 16.0.x):

  • Back/forward should leave the page hydrated and interactive (or trigger a normal new request that hydrates correctly).
  • Verified that downgrading next to 16.0.9 makes the bug disappear. Network shows Cache-Control: no-store, must-revalidate on the document, Chrome cannot serve it from disk cache on back/forward, and the page hydrates as expected.

Suspected cause:

  • PR #91503 (https://github.com/vercel/next.js/pull/91503) removed the devCacheControlNoCache experimental option and hard-coded no-cache for dev HTML responses.
  • Chrome's back/forward navigation is allowed by HTTP/1.1 (and is the documented Chrome behavior) to bypass revalidation for Cache-Control: no-cache and serve from disk cache. With no-store, Chrome cannot disk-cache the response, so this code path is avoided entirely.
  • The disk-cached HTML carries __next_f.push(...) chunks tied to a specific dev-server session/build. When Turbopack's RSC bootstrap tries to consume this stale payload, hydration silently no-ops with no error surfaced.

So while the header change itself is intentional per #91503, it has an unintended interaction with Chrome's back/forward cache semantics that breaks dev-mode UX.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:26 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T8132
  Available memory (MB): 32768
  Available CPU cores: 10
Binaries:
  Node: 24.13.0
  npm: 11.6.2
  Yarn: N/A
  pnpm: 10.28.2
Relevant Packages:
  next: 16.2.3 // There is a newer version (16.2.6) available, upgrade recommended! 
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Turbopack, Runtime

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

  • Tested on Chrome (incognito + with extensions disabled — same result, rules out extensions).
  • Production build (next build && next start) is unaffected.
  • A workaround for app-level fix while waiting for upstream:
    // app/layout.tsx — dev only
    if (process.env.NODE_ENV === "development") {
      // inline script in <head>
      // window.addEventListener('pageshow', e => {
      //   if (e.persisted) return;
      //   const nav = performance.getEntriesByType('navigation')[0];
      //   if (nav?.type === 'back_forward') location.reload();
      // });
    }
  • Setting Cache-Control: no-store from next.config.ts headers() or middleware does not override the dev-server-injected header — Next.js dev rewrites it on the response.
  • Bisected by version: 16.0.9 ✅ unaffected, 16.2.3 ❌ affected. (The transition aligns with PR #91503 merging into 16.1.)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING