Conversation
React needs stable keys between HTML prerender and resume, but unknown route params currently put opaque placeholders in those keys. Next.js then rewrites the serialized postponed state with concrete request values. Use segment name/type for server layout keys and structural paths for the server head key. For /products/[slug], both server passes use slug|d while the browser still uses slug|shoe|d. Keep browser remount behavior and router cache identity unchanged. Remove postponed-state placeholder substitution and its request-params argument. Retain fallback-param metadata for render staging, update existing parser expectations, and document the distinction. Validated with 87 existing Webpack integration tests, 63 unit tests, TypeScript, lint, and a full build. Local Turbopack runs stop before rendering because the installed native binding does not provide the project result shape expected by this canary checkout.
Contributor
Tests PassedCommit: 6878e71 |
Use a single createSegmentKey import for layouts and the head. The default implementation uses structural keys on the server, while a .browser.ts variant re-exports the existing concrete router key function. For /products/[slug], the server retains slug|d across prerender and resume, while the browser uses slug|shoe|d so navigation still resets the appropriate subtree. Compute the layout state key once and reuse it for template, Activity, and dev boundaries. Remove inline server/browser key selection and the separate per-entry React key. Preserve query-only state reuse and browser head keys, and regenerate both Webpack and Turbopack browser-variant alias lists. Verified with 63 existing unit tests and 43 existing Webpack integration tests across dev and production, including fallback-shell resume/hydration, head search params, back/forward state, template remounting, and standalone/edge output. Full JS build, TypeScript, ESLint, Prettier, and generated Rust formatting pass. Turbopack integration remains unverified locally because the available native binding does not match this checkout; it also needs the regenerated alias list compiled into it.
Structural server keys no longer need opaque parameter placeholders or their types to resume React's HTML. Persist just the unknown parameter names for render staging, and parse them into a set. For /products/[slug], the metadata is now ["slug"] instead of [["slug", ["%%drp:slug:...%%", "d"]]]. Use name sets in the request store while retaining the separate placeholder map used by dev prerender validation. Preserve explicit-empty metadata and the platform's metadata-free 4:nullnull state: the former defers no params, while the latter still falls back to the request's staging metadata. Remove the unused serialized-entry type and the stale interpolation comment. Update serialization coverage for HTML and data-only states, scalar and catch-all params, cache compression, and empty/full prelude detection. Verified 71 unit tests and 39 Webpack integration tests across production and dev, including shell upgrades, revalidation, hydration, dev validation, head resumption, and standalone/edge output. Four pre-existing integration tests remain skipped. Build, TypeScript, ESLint, and Prettier pass. Local Turbopack integration remains unverified because the available native binding does not match this checkout.
Add direct coverage for the server and browser segment-key implementations. For example, server keys stay slug|d when an opaque fallback becomes a real slug, while browser keys include the concrete value. Cover catch-all and intercepted segments, distinct names/types, and the different search-param behavior. Delegate static server segments to the existing router cache-key helper with search parameters always excluded. Remove the unused dynamic-param type slot from opaque fallback maps. Resume metadata now persists only param names, so these maps only need to associate each name with its placeholder. Rename the old searchValue local and clarify that parameter wrappers, not the placeholders themselves, control suspension. Update the action-only fallback fixture to recognize names-only postponed metadata. Its old tuple-format assertion caused all three local cases to fail before exercising action execution, revalidation, and notFound handling. Verification: - 126 focused unit tests and 4 snapshots pass in both default and Cache Components/Webpack configurations. - 34 production Webpack tests pass across fallback shells, shell upgrades, action-only fallback resumes, and runtime-search-param head resumes; 4 existing tests remain skipped. - Full workspace build, repository type check, and changed-file lint pass. - The Turbopack action-resume run stops before application rendering because the installed native binding does not match this checkout's project result shape. CI needs to verify it with a matching native build.
gnoff
added a commit
that referenced
this pull request
Sep 19, 2026
Move the matching API onto the prerequisite chain rooted at #98944: structural server keys, build-time generator context, cached fallback-root reads, and adapter fallback query names. Preserve the API's existing history with an integration merge and retain its independently removable diagnostic logging commit. The three prerequisite commits replay without patch changes. The API's added and removed lines also remain identical to its previous diff against the old prerequisite branch. Resolve overlap with canary's config additions and closed-parameter hint plumbing without changing matching semantics. Keep #98944's name-to-placeholder fallback map and structural server keys. For example, a catch-all shell and its resumed render use the same parts|c server key, so the old singleton-array placeholder conversion from #98890 is no longer part of the stack. Verification: full workspace build and repository type check pass; all 222 focused static-paths, segment-key, fallback-param, and postponed-state unit tests pass with four snapshots. Focused Webpack integration coverage passes: 43 production tests across the API, cached generators, existing gSP behavior, fallback root caching, and adapter query output; 26 development tests cover the API and existing static shell validation, with nine snapshots. Existing mode-specific skips remain unchanged. Turbopack integration still needs the matching CI native build.
gnoff
marked this pull request as ready for review
September 19, 2026 21:59
gnoff
added this pull request to stack #98946
September 19, 2026 22:03
This was referenced Sep 19, 2026
gnoff
removed this pull request from stack #98946
September 19, 2026 23:55
gnoff
added this pull request to stack #98951
September 19, 2026 23:55
gnoff
removed this pull request from stack #98951
September 20, 2026 05:46
gnoff
added this pull request to stack #98956
September 20, 2026 05:46
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.
Summary
Use structural React keys during server rendering so an HTML prerender can resume without rewriting React's postponed state when route params become known. Browser keys and router-cache identity are unchanged.
For example,
/products/[slug]previously prerendered layout boundaries with a key containing an opaque slug placeholder. Resuming/products/shoeproduced a different key, so Next.js substitutedshoeinto the serialized React state before handing it back to React. Both server passes now useslug|d. The browser still usesslug|shoe|d, preserving template remounts and back/forward state behavior.The server only renders the active entry at each layout-router position, so it does not need parameter values to distinguish cached browser entries. React keys are not embedded in the HTML; hydration derives its concrete keys from the request's route state.
notFound()with names-only metadata.This refactor is independently landable against
canaryand is now the base of the parameter-matching stack: #98944 → #98891 → #98892 → #98893 → #97393. It supersedes #98890. It retains internal opaque placeholders but removes their role in matching React's postponed state. No new integration fixtures are needed.Verification
Latest cleanup:
fallback-shells,partial-fallback-shell-upgrade,action-only-fallback-resume-data-cache, andresuming-head-runtime-search-param; 4 existing tests remain skipped. The three action-only resume cases now reach and pass their behavioral assertions.Earlier commits also passed existing production and dev Webpack coverage for back/forward state, template remounts, base-path params, nested/parallel/intercepted routes, form-state hydration, and standalone/edge output.
A reviewer verified this head under Turbopack using a native binary built from the same commit: a broader unit selection passed (144 tests, the focused set above plus the remaining router-reducer suites), the
packages/nexttype check was clean, and 33 production e2e tests passed acrossfallback-shells,partial-fallback-shell-upgrade, andaction-only-fallback-resume-data-cache.