Skip to content

Stream Suspense fallbacks during draft mode in App Router #1009

@github-actions

Description

@github-actions

Upstream change

Next.js fixed a regression where pages rendered with draftMode().enable() would block on all I/O instead of streaming Suspense fallbacks. Since Next.js does not generate PPR shells for draft-mode requests, the renderer treats them as a static prerender and waits for the entire tree, even though the response is dynamic and could be streamed.

The fix adds isDraftMode to the conditions that opt the request into dynamic HTML rendering (alongside dev mode and non-SSG routes), so Suspense boundaries flush their fallbacks and the page streams normally.

Relevant diff (packages/next/src/build/templates/app-page.ts):

routeModule.isDev === true ||
// If this is a draft mode request, it supports dynamic HTML.
isDraftMode ||
// If this is not SSG or does not have static paths, then it supports
// dynamic HTML.
!isSSG ||

Why this matters for vinext

vinext renders App Router pages through its own RSC/SSR pipeline (entries/app-rsc-entry.ts and server/app-*.ts helpers). When draft mode is enabled we should make sure draft-mode requests are treated as dynamic and that Suspense fallbacks stream, rather than blocking on allReady like a static prerender. This is a parity item for cache components / "use cache" and any route that mixes draft mode with Suspense.

Suggested work

  • Audit the App Router render path (server/app-*.ts, RSC and SSR entries) to confirm draft-mode requests opt into the dynamic / streaming branch and do not wait for onAllReady before flushing.
  • Port the fixture and test from test/e2e/app-dir/cache-components/cache-components.draft-mode.test.ts (added in the PR) so we have explicit coverage that draft-mode pages stream their loading.tsx / Suspense fallbacks.
  • Verify behavior on both the dev server and the Cloudflare Workers production entry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    nextjs-trackingTracking issue for a Next.js canary change relevant to vinext

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions