fix(app-router): hard navigate stale RSC build payloads#1178
Draft
NathanDrake2406 wants to merge 1 commit into
Draft
fix(app-router): hard navigate stale RSC build payloads#1178NathanDrake2406 wants to merge 1 commit into
NathanDrake2406 wants to merge 1 commit into
Conversation
App Router soft navigation currently accepts any valid RSC payload after deploy. That lets stale tabs decode RSC responses produced by a different build, which can break client navigation when the server and browser artifacts no longer match. The missing invariant was that every RSC response consumed by the browser must identify the build that produced it, and the browser must reject payloads from a different build before handing them to React. Emit a vinext-owned build ID header on App Router RSC responses, preserve it in prefetched and visited response snapshots, and hard navigate when a response is missing or mismatches the current client build ID.
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
packages/vinext/src/server/app-rsc-cache-busting.ts,packages/vinext/src/server/app-browser-entry.ts,packages/vinext/src/shims/navigation.tsWhy
A browser-side App Router navigation must only apply RSC data that was produced by the same server artifact as the current client bundle. Next.js enforces this by initializing a navigation build ID during hydration and falling back to an MPA navigation when a later Flight response belongs to another build. Vinext had content-type and status checks, but no build-artifact compatibility check, so stale tabs could keep using soft navigation across deploy boundaries.
X-Vinext-Build-Idafter middleware headers are merged so app middleware cannot override the framework value.createFromFetch.One PR vs split
This should be one PR. Splitting would either emit unused server metadata without protection, or add a client guard with no reliable build ID to compare. The server header, snapshot preservation, and browser guard are one observable behavior.
What changed
X-Vinext-Build-IdMaintainer review path
packages/vinext/src/server/app-rsc-cache-busting.ts: build ID header constant, compatibility predicate, and RSC hard-navigation target normalization.packages/vinext/src/server/app-browser-entry.ts: checks in server actions, visited response cache, fresh fetch, and prefetch paths before decoding RSC.packages/vinext/src/server/app-page-*.tsandapp-server-action-execution.ts: all App Router RSC response constructors apply the build ID header.packages/vinext/src/shims/navigation.ts: cached/prefetched RSC snapshots preserve the build ID header.Validation
Ran locally:
vp test run tests/app-rsc-cache-busting.test.ts tests/app-page-response.test.ts tests/app-page-cache.test.ts tests/prefetch-cache.test.ts tests/app-browser-entry.test.tsResult: 5 files, 162 tests passed.
vp checkResult: formatting passed, no warnings, lint errors, or type errors.
knip --no-progress.Review feedback addressed:
CachedRscResponsedeclaration now matches runtime shape.Risk / compatibility
Non-goals
References