Skip to content

perf(nitro,schema): inline payload in HTML for cached routes + add payloadExtraction: 'client'#34410

Merged
danielroe merged 5 commits intomainfrom
perf/inlined-payloads
Mar 4, 2026
Merged

perf(nitro,schema): inline payload in HTML for cached routes + add payloadExtraction: 'client'#34410
danielroe merged 5 commits intomainfrom
perf/inlined-payloads

Conversation

@danielroe
Copy link
Copy Markdown
Member

🔗 Linked issue

📚 Description

when a cached route (ISR/SWR) is rendered at runtime with payload extraction enabled, the HTML references an external _payload.json.

the browser immediately fetches this as a second request, which triggers a full SSR re-render of the same page just to extract the data portion. in a serverless environment, this can spin up a second lambda before the first response has even finished streaming...

this PR addresses this in two ways:

  1. adds a new payloadExtraction: 'client' mode that inlines the full payload in the initial HTML response while still generating _payload.json for client-side navigation (bypassing the issue entirely)
  2. adds a runtime in-memory LRU payload cache so that _payload.json requests (from client-side navigation) can be served without a full re-render when the HTML was already rendered in the same process

The new payloadExtraction: 'client' is only default with compatibilityVersion: 5, to avoid a breaking change, but the runtime cache should still solve the issue for these users.

context

surveying the issues, spotted some requests for extraction even on the initial render

hence allowing 'true' to force extraction on server side as well. we might revisit as I think there's plenty of space for optimisation here

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 1, 2026

Open in StackBlitz

@nuxt/kit

npm i https://pkg.pr.new/@nuxt/kit@34410

@nuxt/nitro-server

npm i https://pkg.pr.new/@nuxt/nitro-server@34410

nuxt

npm i https://pkg.pr.new/nuxt@34410

@nuxt/rspack-builder

npm i https://pkg.pr.new/@nuxt/rspack-builder@34410

@nuxt/schema

npm i https://pkg.pr.new/@nuxt/schema@34410

@nuxt/vite-builder

npm i https://pkg.pr.new/@nuxt/vite-builder@34410

@nuxt/webpack-builder

npm i https://pkg.pr.new/@nuxt/webpack-builder@34410

commit: 0507d97

@coderabbitai

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/schema/src/types/schema.ts`:
- Around line 1134-1136: Update the JSDoc for the payloadExtraction property to
reflect both defaults: keep the historical "@default true" and add that when
future.compatibilityVersion >= 5 the resolver default becomes "'client'";
reference the payloadExtraction field and mention the condition using
future.compatibilityVersion so readers know migration behaviour explicitly
(e.g., "@default true — becomes 'client' when future.compatibilityVersion >=
5").

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96bd51a and 6ee549f.

📒 Files selected for processing (6)
  • packages/nitro-server/src/index.ts
  • packages/nitro-server/src/runtime/handlers/renderer.ts
  • packages/nitro-server/src/runtime/utils/cache.ts
  • packages/nitro-server/src/runtime/utils/renderer/payload.ts
  • packages/schema/src/config/experimental.ts
  • packages/schema/src/types/schema.ts

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 1, 2026

Merging this PR will not alter performance

✅ 20 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing perf/inlined-payloads (cc274d9) with main (934c26f)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@danielroe danielroe force-pushed the perf/inlined-payloads branch from f07bb93 to cf1a770 Compare March 4, 2026 20:53
@danielroe danielroe enabled auto-merge March 4, 2026 20:57
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/nitro-server/src/runtime/handlers/renderer.ts (1)

97-100: ⚠️ Potential issue | 🟠 Major

payloadExtraction: false allows payload extraction on cached runtime routes.

The extraction condition at lines 97–100 handles prerender and runtime cached routes separately. The prerender branch correctly checks NUXT_PAYLOAD_EXTRACTION, but the runtime branch (line 99) only checks NUXT_RUNTIME_PAYLOAD_EXTRACTION without verifying the global NUXT_PAYLOAD_EXTRACTION flag. This permits payload extraction to trigger when the user sets payloadExtraction: false, contradicting the documented behaviour that extraction should be "disabled entirely" in that case.

When triggered, _PAYLOAD_EXTRACTION causes downstream side-effects: adding prerender headers (line 179), gating payload preloads (line 224), and affecting script placement (line 299).

Fix
  const _PAYLOAD_EXTRACTION = !ssrContext.noSSR && (
    (import.meta.prerender && NUXT_PAYLOAD_EXTRACTION)
-   || (NUXT_RUNTIME_PAYLOAD_EXTRACTION && (routeOptions.isr || routeOptions.cache))
+   || (NUXT_PAYLOAD_EXTRACTION && NUXT_RUNTIME_PAYLOAD_EXTRACTION && (routeOptions.isr || routeOptions.cache))
  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nitro-server/src/runtime/handlers/renderer.ts` around lines 97 -
100, The conditional that sets _PAYLOAD_EXTRACTION allows runtime cached routes
to extract payloads even when the global NUXT_PAYLOAD_EXTRACTION is false;
update the expression initializing _PAYLOAD_EXTRACTION to require the global
NUXT_PAYLOAD_EXTRACTION for both branches so payload extraction only runs when
NUXT_PAYLOAD_EXTRACTION is true and either (import.meta.prerender &&
NUXT_PAYLOAD_EXTRACTION) or (NUXT_RUNTIME_PAYLOAD_EXTRACTION &&
NUXT_PAYLOAD_EXTRACTION && (routeOptions.isr || routeOptions.cache)); modify the
initialization where _PAYLOAD_EXTRACTION is defined to include this additional
check so downstream logic that reads _PAYLOAD_EXTRACTION (headers, payload
preloads, script placement) respects the global payloadExtraction flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/nitro-server/src/runtime/handlers/renderer.ts`:
- Around line 97-100: The conditional that sets _PAYLOAD_EXTRACTION allows
runtime cached routes to extract payloads even when the global
NUXT_PAYLOAD_EXTRACTION is false; update the expression initializing
_PAYLOAD_EXTRACTION to require the global NUXT_PAYLOAD_EXTRACTION for both
branches so payload extraction only runs when NUXT_PAYLOAD_EXTRACTION is true
and either (import.meta.prerender && NUXT_PAYLOAD_EXTRACTION) or
(NUXT_RUNTIME_PAYLOAD_EXTRACTION && NUXT_PAYLOAD_EXTRACTION && (routeOptions.isr
|| routeOptions.cache)); modify the initialization where _PAYLOAD_EXTRACTION is
defined to include this additional check so downstream logic that reads
_PAYLOAD_EXTRACTION (headers, payload preloads, script placement) respects the
global payloadExtraction flag.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0b670d24-ad80-4075-a7ba-83891c1962f3

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5c829 and cf1a770.

📒 Files selected for processing (7)
  • docs/3.guide/6.going-further/1.experimental-features.md
  • packages/nitro-server/src/index.ts
  • packages/nitro-server/src/runtime/handlers/renderer.ts
  • packages/nitro-server/src/runtime/utils/cache.ts
  • packages/nitro-server/src/runtime/utils/renderer/payload.ts
  • packages/schema/src/config/experimental.ts
  • packages/schema/src/types/schema.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/nitro-server/src/runtime/utils/renderer/payload.ts
  • packages/schema/src/config/experimental.ts
  • packages/nitro-server/src/index.ts

@danielroe danielroe added this pull request to the merge queue Mar 4, 2026
Merged via the queue into main with commit e1dade2 Mar 4, 2026
55 of 56 checks passed
@danielroe danielroe deleted the perf/inlined-payloads branch March 4, 2026 21:45
This was referenced Mar 4, 2026
danielroe added a commit that referenced this pull request Mar 9, 2026
…ayloadExtraction: 'client'` (#34410)

Co-authored-by: Sébastien Chopin <seb@nuxt.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
@github-actions github-actions bot mentioned this pull request Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants