Skip to content

App Router: replace prerender HTML buffering with SSR metadata readiness #1795

Description

@NathanDrake2406

Problem

PR #1788 fixes searchParams static-bailout correctness by buffering the prerender HTML stream in renderAppPageLifecycle() before finalising cache metadata and headers.

That is a correct local fix, but it is not the ideal long-term contract. The underlying sequencing problem is that some app-page cache metadata is only discovered once SSR consumes the HTML/RSC stream, while prerender headers and cache policy must be known before the response is returned.

The current workaround is effectively:

const bufferedHtml = await readStreamAsText(htmlStream)
htmlStream = createBufferedHtmlStream(bufferedHtml)
await settleCapturedRscRenderForCacheMetadata(...)

This is scoped to isPrerender === true, so it should not affect runtime request streaming, but it still materialises the full HTML output during prerender and could become a bad precedent if copied into runtime paths.

Desired shape

Replace implicit “consume the HTML stream to discover metadata” behaviour with an explicit readiness contract between the SSR handler and the app-page render lifecycle.

One possible shape:

type AppSsrRenderResult = {
  htmlStream: ReadableStream<Uint8Array>
  metadataReady: Promise<void>
  capturedRscData: Promise<ArrayBuffer> | null
}

Then renderAppPageLifecycle() can await metadataReady during prerender before applying cache-life/header decisions, without buffering the complete HTML string.

Constraints

  • Do not buffer runtime user responses.
  • Preserve streaming behaviour for non-prerender app-page responses.
  • Preserve correct prerender headers when cache metadata is discovered during SSR/RSC consumption.
  • Preserve complete render observations for both HTML and captured RSC cache artifacts.
  • Keep the ownership boundary clear: SSR should expose when render-side metadata effects have settled; app-page render lifecycle should not have to infer that by draining HTML.

Acceptance criteria

  • renderAppPageLifecycle() no longer needs to call readStreamAsText(htmlStream) solely to settle prerender metadata.
  • The SSR/app-page boundary exposes an explicit metadata-settlement signal.
  • Tests cover the current failure mode: metadata/cache-life discovered during HTML stream consumption still affects prerender cache headers.
  • Tests prove runtime app-page streaming paths are not buffered.
  • The allowed buffering locations, if any remain, are documented as prerender-only and not a general render lifecycle pattern.

Related

Follow-up from #1788. This should not block #1788; that PR should ship the scoped correctness fix first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions