vercel / vercel/next.js

Pages Router hydration causes an extra client render on full page load when any rewrite is configured, including non-rewritten routes

Open
#93,091 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Linking and Navigating Pages Router
Dominant language
JavaScript
Stars
142k
Forks
32.5k
Avg merge
2d 14h
Merged PRs (30d)
351

Description

Link to the code that reproduces this issue

https://github.com/gurkerl83/next-pages-router-global-rewrite-rerender-repro

To Reproduce
  1. Clone the linked reproduction.
  2. The reproduction configures exactly one rewrite: /rewritten -> /target.
  3. Run:
pnpm install
pnpm build
pnpm start
  1. Open / directly in the browser, or reload /.
  2. Open /rewritten directly in the browser, or reload /rewritten.
  3. Check the browser console.

Observed result:

  • _app logs two client renders on /
  • _app logs two client renders on /rewritten

Important notes:

  • This does not reproduce in next dev.
  • Client-side navigation with <Link> is not the repro path here.
  • The extra render happens during the initial browser hydration path on a full page load or reload.
  • The rendered pages do not use useRouter().
  • The on-page render counters use plain React refs.
  • _app reads Router.router only for logging.
Current vs. Expected behavior

Current behavior:

In the linked reproduction, the app has one rewrite: /rewritten -> /target.

On a full page load or reload in production:

  • /rewritten gets an extra client render
  • / also gets an extra client render, even though / is not rewritten

Expected behavior:

I am not asking to remove rewrite-aware hydration reconciliation entirely.

I would expect the extra Pages Router hydration rerender to happen only when the current request actually depends on rewrite-derived route or query reconciliation.

So in this reproduction, I would expect:

  • /rewritten: rewrite-specific reconciliation if needed
  • /: a single client render
Provide environment information
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:54:55 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T6031
  Available memory (MB): 65536
  Available CPU cores: 16
Binaries:
  Node: 22.6.0
  npm: 10.8.2
  Yarn: 1.22.22
  pnpm: 10.18.1
Relevant Packages:
  next: 16.3.0-canary.2 // Latest available version is detected (16.3.0-canary.2).
  eslint-config-next: N/A
  react: 19.2.5
  react-dom: 19.2.5
  typescript: 6.0.3
Next.js Config:
  output: N/A
Which area(s) are affected? (Select all that apply)

Pages Router, Linking and Navigating

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

next build (local), next start (local)

Additional context

I verified this on the latest canary: 16.3.0-canary.2.

This seems related to the older closed issue:

That issue was closed as expected behavior because rewrites may require a post-hydration query update for static pages. This reproduction shows a narrower problem: the same extra rerender also happens on /, even though / is not rewritten.

The reproduction is intentionally minimal:

  • one rewrite: /rewritten -> /target
  • / is static and not rewritten
  • the rendered pages do not use useRouter()
  • _app only logs Router.router state for debugging

So the issue here is not just “rewritten routes rerender”, but that the presence of any rewrite appears to trigger the hydration rerender path for unrelated static routes too.

What I think should happen instead:

  • keep rewrite-aware hydration reconciliation for requests that actually need it
  • avoid the extra hydration rerender for requests whose effective route identity and query are already correct

This reproduction is meant to show that the current trigger appears to be app-global, while the behavior should be request-local.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked reproduction and inspect the Pages Router hydration path exercised by the _app render logs. Run pnpm install, pnpm build, and pnpm start, then compare direct loads of / and /rewritten in the browser console. Done means rewrite reconciliation remains for routes that need it while / has one client render on a production load.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, next.js, react
Domain
frontend, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.