[PR #617] [CLOSED] fix: skip ISR cache write for RSC requests when dynamic APIs are used #718

Closed
opened 2026-05-06 13:09:46 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/617
Author: @NathanDrake2406
Created: 3/21/2026
Status: Closed

Base: mainHead: fix/rsc-dynamic-usage-cache-bypass


📝 Commits (4)

  • 126fd47 test: add ISR + searchParams dynamic usage regression tests
  • b714e5d fix: skip ISR cache write for RSC requests when dynamic APIs are used
  • 899af8e fix: add deferred dynamic usage check for APIs called during RSC rendering
  • cb63a66 test: update entry template snapshots for dynamic usage guard

📊 Changes

4 files changed (+200 additions, -14 deletions)

View changed files

📝 packages/vinext/src/entries/app-rsc-entry.ts (+17 -2)
📝 tests/__snapshots__/entry-templates.test.ts.snap (+102 -12)
📝 tests/app-router.test.ts (+60 -0)
tests/fixtures/app-basic/app/isr-dynamic-search/page.tsx (+21 -0)

📄 Description

Summary

  • RSC response path (client-side navigation) was writing to ISR cache unconditionally, ignoring dynamic API usage (searchParams, headers(), cookies(), noStore()). The HTML path correctly checked consumeDynamicUsage() before caching, but the RSC path returned before that check ever ran.
  • Pages with both revalidate and dynamic APIs (like searchParams or headers()) served stale cached data on client-side navigations — the first request's content was cached under the pathname key and returned for all subsequent RSC requests regardless of different search params.
  • Two-phase fix: early consumeDynamicUsage() catches APIs called during element construction (searchParams), deferred check inside the cache write promise catches APIs called during stream rendering (headers, cookies, noStore).

Closes #588

Test plan

  • New fixture page (isr-dynamic-search) with revalidate=60 + searchParams access
  • Integration tests: RSC requests with different searchParams get fresh renders, no X-Vinext-Cache header
  • Integration tests: HTML responses also skip ISR cache for dynamic pages
  • Code generation test: asserts both early and deferred consumeDynamicUsage() guards exist
  • All 270 existing app-router.test.ts tests pass
  • All generateRscEntry ISR code generation tests pass
  • All features.test.ts ISR tests pass
  • pnpm run check clean
  • Manually verified on a real app (headers() + noStore() + revalidate=604800) via wrangler dev

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/617 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 3/21/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/rsc-dynamic-usage-cache-bypass` --- ### 📝 Commits (4) - [`126fd47`](https://github.com/cloudflare/vinext/commit/126fd4781b134ea017ac2d5dcdbcc770eaa9bdaf) test: add ISR + searchParams dynamic usage regression tests - [`b714e5d`](https://github.com/cloudflare/vinext/commit/b714e5d3b8b8446bd9bb860c7fd685bed20d6f93) fix: skip ISR cache write for RSC requests when dynamic APIs are used - [`899af8e`](https://github.com/cloudflare/vinext/commit/899af8e229b4891aa18dc138be8e8e99b1100edf) fix: add deferred dynamic usage check for APIs called during RSC rendering - [`cb63a66`](https://github.com/cloudflare/vinext/commit/cb63a66980726e8d766a50b317bde0bcbdc90c71) test: update entry template snapshots for dynamic usage guard ### 📊 Changes **4 files changed** (+200 additions, -14 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/entries/app-rsc-entry.ts` (+17 -2) 📝 `tests/__snapshots__/entry-templates.test.ts.snap` (+102 -12) 📝 `tests/app-router.test.ts` (+60 -0) ➕ `tests/fixtures/app-basic/app/isr-dynamic-search/page.tsx` (+21 -0) </details> ### 📄 Description ## Summary - RSC response path (client-side navigation) was writing to ISR cache unconditionally, ignoring dynamic API usage (`searchParams`, `headers()`, `cookies()`, `noStore()`). The HTML path correctly checked `consumeDynamicUsage()` before caching, but the RSC path returned before that check ever ran. - Pages with both `revalidate` and dynamic APIs (like `searchParams` or `headers()`) served stale cached data on client-side navigations — the first request's content was cached under the pathname key and returned for all subsequent RSC requests regardless of different search params. - Two-phase fix: early `consumeDynamicUsage()` catches APIs called during element construction (searchParams), deferred check inside the cache write promise catches APIs called during stream rendering (headers, cookies, noStore). Closes #588 ## Test plan - [x] New fixture page (`isr-dynamic-search`) with `revalidate=60` + `searchParams` access - [x] Integration tests: RSC requests with different searchParams get fresh renders, no `X-Vinext-Cache` header - [x] Integration tests: HTML responses also skip ISR cache for dynamic pages - [x] Code generation test: asserts both early and deferred `consumeDynamicUsage()` guards exist - [x] All 270 existing `app-router.test.ts` tests pass - [x] All `generateRscEntry` ISR code generation tests pass - [x] All `features.test.ts` ISR tests pass - [x] `pnpm run check` clean - [x] Manually verified on a real app (`headers()` + `noStore()` + `revalidate=604800`) via `wrangler dev` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:09:46 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#718
No description provided.