nextjs - ✅(Solved) Fix Quit / reopen Safari + back navigation - Content of latest visited page in history is persisted [1 pull requests, 8 comments, 3 participants]

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…
GitHub stats
vercel/next.js#90080Fetched 2026-04-08 00:20:51
View on GitHub
Comments
8
Participants
3
Timeline
19
Reactions
0
Timeline (top)
commented ×7labeled ×4cross-referenced ×2closed ×1

Root Cause

Reproducible on browser(s):

  • MacOS: Safari browser
  • iOS: Any browser (assumed because of safari under the hood)

Fix Action

Fixed

PR fix notes

PR #90083: Handle null history.state in client-side router popstate handler

Description (problem / solution / changelog)

What?

Handle null history.state in the client-side router's popstate handler.

Why?

When pushState or replaceState is called outside of Next.js with a null state (or the initial history entry has no state), navigating back/forward to that entry fires a popstate event with event.state === null. Previously, the onPopState handler returned early without doing anything, leaving the router tree completely out of sync with the browser URL — usePathname(), useSearchParams(), etc. would return stale values.

How?

When event.state is null, call window.location.reload() to perform a hard navigation, the same behavior as when a non-Next.js history entry is encountered (!event.state.__NA). This ensures the router always returns to a consistent state.

Added an e2e test that:

  1. Navigates to a second page via client-side Link
  2. Pushes history entries with truly null state (via History.prototype.pushState to bypass the Next.js patch)
  3. Goes back and verifies the page correctly reloads

Fixes #90080

Changed files

  • packages/next/src/client/components/app-router.tsx (modified, +5/-1)
  • test/e2e/app-dir/popstate-null-state/app/layout.tsx (added, +8/-0)
  • test/e2e/app-dir/popstate-null-state/app/other/page.tsx (added, +8/-0)
  • test/e2e/app-dir/popstate-null-state/app/page.tsx (added, +22/-0)
  • test/e2e/app-dir/popstate-null-state/next.config.js (added, +6/-0)
  • test/e2e/app-dir/popstate-null-state/popstate-null-state.test.ts (added, +84/-0)

Code Example

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.2.0: Tue Nov 18 21:07:05 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6020
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 20.19.5
  npm: 10.8.2
  Yarn: N/A
  pnpm: 10.11.0
Relevant Packages:
  next: 16.2.0-canary.48 // Latest available version is detected (16.2.0-canary.48).
  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://codesandbox.io/p/devbox/quiet-tdd-rzgf2d

To Reproduce

  1. Open Safari browser
  2. Make sure Safari resumes with last session tabs when opening
    • On MacOS: configure the "Safari opens with" setting to "All windows from last session" or "All non-private windows from last session" (Safari > Settings > General > "Safari opens with")
    • On iOS this should be default behavior, haven't found a specific setting related to it
  3. Open the reproduction codesandbox standalone preview (https://rzgf2d-3000.csb.app/)
  4. Click the "Route 1" link
  5. Quit Safari browser
    • On MacOS via Toolbar > Right click Safari browser icon > Select "Quit"
    • On iOS:
      • Swipe up from the bottom to the middle of your screen and hold until you see the App Switcher
      • Swipe the Safari iOS browser app screen up and out of your screen to quit it
  6. Re-open Safari browser
    • Assert the "Route 1" codesandbox preview page is shown (or select that tab after reopening)
    • Assert the back button seems interactable and is not disabled
    • Assert the address bar ends with: /route-1
  7. Click the back button
    • Assert the "Route 1" page content is still showing (scroll position might change)
    • Assert the address bar actually points at /

Current vs. Expected behavior

Following the steps of reproduction, I would expect the content of the "Home" route to be shown after using the back button on the "Route 1" route, but the content of the "Route 1" route is persisted.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.2.0: Tue Nov 18 21:07:05 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6020
  Available memory (MB): 16384
  Available CPU cores: 12
Binaries:
  Node: 20.19.5
  npm: 10.8.2
  Yarn: N/A
  pnpm: 10.11.0
Relevant Packages:
  next: 16.2.0-canary.48 // Latest available version is detected (16.2.0-canary.48).
  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)

Linking and Navigating, Pages Router

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

next dev (local), next start (local), Vercel (Deployed)

Additional context

General description: Opening a Next.JS site in Safari browser, navigating to different pages, quitting Safari browser and reopening it (resuming from that Next.JS site) and then trying to use the browser back button results in the actual route in address bar to update correctly, scroll might be updated (assumed restoration), but the contents of the latest page that was visited is persisted - never showing the actual previous pages content.

This mainly impacts users on iOS as just swiping away the browser app, while later reopening it, while you keep a Next.JS powered site open in a tab will result in this situation (assumed common browsing behavior) - With reported confusion and frustration for users as a result.

Reproducible on operating systems (including, but unknown if limited to):

  • MacOS Sequoia (15)
  • MacOS Tahoe (26)
  • iOS 26

Reproducible on browser(s):

  • MacOS: Safari browser
  • iOS: Any browser (assumed because of safari under the hood)

Reproduction steps tested on Chrome and Firefox on MacOS and behavior is as expected: pages back in history show as expected after quit and reopening of the browser.

I've not as of yet been able to pinpoint a specific Next.JS version that introduced this behavior, but it does affect both the Pages and App router in various Next.JS versions. It happens both when using next/link and regular anchor tags.

Versions / routers of Next.JS in projects where I've reproduced this issue:

  • Next.JS ^12.2.0 - Pages router - Hosted on vercel
  • Next.JS ^14.2.3 - Pages router - Hosted on vercel
  • Next.JS ^14.2.35 - App router - Hosted on vercel
  • Next.JS 15.5.9 - Pages router - Hosted on vercel
    • Tested local dev / build + start of this version, same behavior
  • Next.JS ^16.1.6 - App router - Hosted on vercel

Note: Similar behavior has anecdotally been reported to also apply when leaving a Next.JS site in iOS Safari browser tab open for long in the background and returning to it - reported duration was 3 hours, not reproduced yet, but assumed to be caused by similar underlying issue.

Note: So far this affects any Next.JS powered site I've tried to reproduce with, including https://vercel.com/ (tested through https://vercel.com/blog and navigating to blog post)

extent analysis

Fix: Detect Safari’s bfcache restore and force a client‑side

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

nextjs - ✅(Solved) Fix Quit / reopen Safari + back navigation - Content of latest visited page in history is persisted [1 pull requests, 8 comments, 3 participants]