nextjs - 💡(How to fix) Fix Middleware rewrites cause repeated RSC fetches for previously visited search-param URLs [1 comments, 2 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#92175Fetched 2026-04-08 01:56:44
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
0
Author
Timeline (top)
closed ×1commented ×1labeled ×1locked ×1

When middleware rewrites a short URL to a deeper internal path and <Link prefetch={false}> is used, every search-param navigation triggers an RSC fetch to the server — even for previously visited URLs. The same URL with the same _rsc key is fetched repeatedly instead of being served from the client-side segment cache.

Root Cause

The navigation flow:

  1. navigateImpl misses on the route cache (different search params = different key)
  2. deprecated_requestOptimisticRouteCacheEntry succeeds — finds the base route
  3. navigateUsingPrefetchedRouteTree is used (correct)
  4. spawnDynamicRequests fires because dynamicRequestTree is non-null (the page segment diverges)
  5. The RSC response data is written to the segment/BFCache
  6. On the next navigation to the same URL, the segment cache lookup misses and a new fetch is triggered

The segment cache miss likely occurs because the middleware rewrite causes a varyPath mismatch between the write (which uses the server response's route tree) and the read (which uses the optimistic route tree). The optimistic tree is constructed from the hydrated route, while the server response includes the rewritten path segments, producing different cache keys.

Fix Action

Fix / Workaround

This is a sibling issue to the scroll bug fixed in #92172. Same middleware rewrite pattern, same repro app. The scroll bug was about scroll={false} being dropped during SERVER_PATCH retries. This issue is about the segment cache not being reusable across navigations.

RAW_BUFFERClick to expand / collapse

Summary

When middleware rewrites a short URL to a deeper internal path and <Link prefetch={false}> is used, every search-param navigation triggers an RSC fetch to the server — even for previously visited URLs. The same URL with the same _rsc key is fetched repeatedly instead of being served from the client-side segment cache.

Reproduction

Repo: https://github.com/damusnet/next-middleware-rewrite-scroll-bug

Deployment: https://next-scroll-repro.vercel.app/

Steps:

  1. Open the deployment, open DevTools Network tab
  2. Click "Item 11" — observe one RSC fetch (?item=10&_rsc=1k7fz)
  3. Click "Item 5" — observe one RSC fetch (?item=4&_rsc=...)
  4. Click "Item 11" again — observe another RSC fetch for ?item=10&_rsc=1k7fz (identical to step 2)

Expected: step 4 should be served from the client-side segment cache with no network request.

Conditions:

  1. Middleware rewrites a short URL to a deeper internal path (common in i18n/multi-tenant apps)
  2. <Link prefetch={false} href="?param=value">
  3. Deployed on Vercel (ISR) — does not reproduce on local next start

Setup:

  • Middleware rewrites / to /en/r/123
  • Page at app/[locale]/r/[id]/page.tsx with revalidate = 60 and generateStaticParams = () => []

Analysis

The navigation flow:

  1. navigateImpl misses on the route cache (different search params = different key)
  2. deprecated_requestOptimisticRouteCacheEntry succeeds — finds the base route
  3. navigateUsingPrefetchedRouteTree is used (correct)
  4. spawnDynamicRequests fires because dynamicRequestTree is non-null (the page segment diverges)
  5. The RSC response data is written to the segment/BFCache
  6. On the next navigation to the same URL, the segment cache lookup misses and a new fetch is triggered

The segment cache miss likely occurs because the middleware rewrite causes a varyPath mismatch between the write (which uses the server response's route tree) and the read (which uses the optimistic route tree). The optimistic tree is constructed from the hydrated route, while the server response includes the rewritten path segments, producing different cache keys.

Related

This is a sibling issue to the scroll bug fixed in #92172. Same middleware rewrite pattern, same repro app. The scroll bug was about scroll={false} being dropped during SERVER_PATCH retries. This issue is about the segment cache not being reusable across navigations.

Environment

  • Next.js 16.2.0
  • Vercel deployment
  • App Router with middleware

extent analysis

TL;DR

The most likely fix involves addressing the varyPath mismatch caused by middleware rewrites, potentially by adjusting the cache key generation to account for rewritten paths.

Guidance

  • Investigate the varyPath calculation in the segment cache implementation to understand how it handles rewritten paths.
  • Consider modifying the cache key generation to include the rewritten path segments, ensuring consistency between write and read operations.
  • Verify that the revalidate option is correctly configured for the page, as it may impact cache behavior.
  • Test the application with different middleware rewrite configurations to isolate the issue and validate potential fixes.

Example

No specific code snippet is provided, as the issue requires a deeper understanding of the Next.js and Vercel implementation details.

Notes

The fix may require changes to the Next.js or Vercel configuration, or potentially updates to the application code to handle the middleware rewrites correctly. The issue is specific to the App Router with middleware and Vercel deployment, so solutions may not apply to other environments.

Recommendation

Apply a workaround by adjusting the cache key generation to account for rewritten paths, as upgrading to a fixed version is not explicitly mentioned in the issue. This approach allows for a targeted fix without relying on external version updates.

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