[GH-ISSUE #1009] Stream Suspense fallbacks during draft mode in App Router #220

Open
opened 2026-05-06 12:38:19 +02:00 by BreizhHardware · 0 comments

Originally created by @github-actions[bot] on GitHub (May 2, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/1009

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.
Originally created by @github-actions[bot] on GitHub (May 2, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/1009 ## 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. - Commit: https://github.com/vercel/next.js/commit/aacf6e19e710aebbfa1dbdf93558b37caa3d290b - PR: https://github.com/vercel/next.js/pull/93417 Relevant diff (`packages/next/src/build/templates/app-page.ts`): ```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.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#220
No description provided.