Skip to content

fix(router): do not inherit shallow flag from history state on browser back/forward (popstate)#93870

Open
sleitor wants to merge 1 commit into
vercel:canaryfrom
sleitor:fix-93844
Open

fix(router): do not inherit shallow flag from history state on browser back/forward (popstate)#93870
sleitor wants to merge 1 commit into
vercel:canaryfrom
sleitor:fix-93844

Conversation

@sleitor
Copy link
Copy Markdown
Contributor

@sleitor sleitor commented May 15, 2026

What

Fixes #93844

When router.replace() is called with shallow: true, Next.js stores the shallow flag inside window.history.state for that history entry. This is correct for the immediate navigation — it suppresses the getServerSideProps call as intended.

However, the flag is never cleared, so when the user later navigates back (or forward) via the browser, the onPopState handler reads options.shallow from the stored history state and re-applies it, incorrectly skipping the data fetch again.

How

In the onPopState handler, force shallow: false regardless of what is stored in the history state:

// Before
shallow: options.shallow && this._shallow,

// After — browser back/forward must never be shallow
shallow: false,

Browser back/forward navigations (popstate events) should always trigger a fresh getServerSideProps call. The _shallow flag in the history state was only meant to suppress the fetch at the time of the original replace/push call.

Testing

Added a regression test to the existing client-shallow-routing E2E suite that:

  1. Visits a page
  2. Calls router.replace() with shallow: true (no data fetch expected)
  3. Navigates to another page
  4. Presses browser back — verifies that getServerSideProps is called (new random value)

Related

When router.replace() is called with shallow:true, Next.js stores the
shallow flag inside the window.history state for that entry. This is
correct for the immediate navigation, but when the user later navigates
back via the browser (popstate), the onPopState handler was reading
options.shallow from the history state and re-applying it, causing
getServerSideProps to be skipped again on browser back/forward.

Fix: always force shallow:false in the onPopState handler. Browser
back/forward navigation should never be shallow — the stored flag was
only meant to suppress the data fetch at the time of the original
replace/push call.

Adds a regression test to the client-shallow-routing test suite.

Fixes vercel#93844
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

router.replace with shallow: true persists shallow flag in history state, causing getServerSideProps to be skipped on browser back navigation

1 participant