-
Notifications
You must be signed in to change notification settings - Fork 30.5k
Description
Link to the code that reproduces this issue
https://github.com/Elusive7733/nextjs-router-cache-search-params-bug
To Reproduce
- Clone the repo:
git clone https://github.com/Elusive7733/nextjs-router-cache-search-params-bug pnpm install && pnpm build && pnpm start- Open http://localhost:3000/home?tab=overview
- Open DevTools Network tab, filter by "Fetch/XHR"
- Click "Listings" → observe RSC network request
- Click "Home" → observe RSC request (should have been cached from prefetch)
- Click "Listings" again → another RSC request (never cached)
The app has 3 fully static pages (no cookies(), headers(), or searchParams usage) linked with search params:
<Link href="/home?tab=overview">Home</Link>
<Link href="/listings?tab=board">Listings</Link>
<Link href="/investors?tab=vetted">Investors</Link>
Key observation: The page you hard-reload on is always cached (seeded entry). Pages navigated to via client-side navigation are never cached, every click triggers a full RSC fetch.
Removing the search params from the href (e.g. href="/listings" instead of href="/listings?tab=board") makes caching work correctly.
Current vs. Expected behavior
Current: Every client-side navigation to a static page triggers a full RSC fetch when the <Link> href includes search params, even though:
- The page is fully static (prerendered)
staleTimes.dynamic: 30is configured- The response includes
x-nextjs-stale-time: 4294967294(~136 years) - The prefetch response returns
prerendered: true
Expected: After the initial prefetch, subsequent navigations within the stale time window should be served from the Router Cache with zero network requests - the same behavior as links without search params, or links with prefetch={true}.
Root cause in prefetch-cache-utils.js:
createLazyPrefetchEntrycreates an AUTO prefetch with cache key/listings(search params excluded for AUTO)- Prefetch response returns
prerendered: true→ entry'skindis upgraded to FULL, but the cache key stays/listings(not updated to/listings?tab=board) - On navigation,
getExistingCacheEntrylooks up/listings?tab=board(with params) → cache miss - Fallback finds
/listingsentry but marks italiased: true→ only loading boundary used → full RSC fetch
Workaround: <Link href="/listings?tab=board" prefetch={true}> - forces FULL prefetch from the start, which keys with search params immediately
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.2.0: Tue Nov 18 21:08:48 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T8132
Available memory (MB): 16384
Available CPU cores: 10
Binaries:
Node: 22.14.0
npm: 10.9.2
Yarn: 1.22.22
pnpm: 10.24.0
Relevant Packages:
next: 15.5.7 // An outdated version detected (latest is 16.1.6), upgrade is highly recommended!
eslint-config-next: N/A
react: 19.1.2
react-dom: 19.1.2
typescript: 5.9.3
Next.js Config:
output: N/A
⚠ An outdated version detected (latest is 16.1.6), upgrade is highly recommended!
Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
Read more - https://nextjs.org/docs/messages/opening-an-issueWhich area(s) are affected? (Select all that apply)
Linking and Navigating
Which stage(s) are affected? (Select all that apply)
Vercel (Deployed), next start (local), next dev (local)
Additional context
- Affects 15.x stable only. Verified that 16.x canary (
16.2.0-canary.45) has a rewritten segment-cache architecture withFallbackwildcard tokens that handles this correctly. A
backport to 15.x would help the many teams still on stable. - Not reproducible in dev mode (
getExistingCacheEntryhas aNODE_ENV !== 'development'guard on the aliased fallback path) staleTimesconfig has no effect — the cache misses at the key lookup level before stale time is ever checked- Related but different: Prefetch on the same pathname with different query params is ignored #47550 (prefetch with different query params ignored), Router Cache entry doesn't work when query params contain %20 #72927 (URL encoding in cache keys)
Tested on 16.2.0-canary.45, the bug is fixed in canary due to the new segment-cache architecture with Fallback wildcard tokens. However, this affects all users on 15.x stable with no documented workaround.
Workaround for 15.x: Add prefetch={true} to <Link> components that include search params in the href.
Filing this for:
- Awareness - this is a common pattern (tabs, filters via search params) with no documentation about the caching pitfall
- Potential 15.x backport consideration
- Searchability — so others hitting this find the workaround