nextjs - ✅(Solved) Fix Next / React 19.2 suspense boundary outlining bug [3 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#91806Fetched 2026-04-08 01:16:11
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1issue_type_added ×1labeled ×1

Root Cause

Root Cause

Fix Action

Fix / Workaround

The 12800 number is the default, but can be configured with the progressiveChunkSize option on renderToReadableStream (docs). The workaround is to set progressiveChunkSize: Infinity.

Unfortunately, the React team hasn't commented on whether the behavior is intended or not, but at least pure React users are able to use the above described workaround.

PR fix notes

PR #33027: [Fizz] Enable the progressiveChunkSize option

Description (problem / solution / changelog)

Since the very beginning we have had the progressiveChunkSize option but we never actually took advantage of it because we didn't count the bytes that we emitted. This starts counting the bytes by taking a pass over the added chunks each time a segment completes.

That allows us to outline a Suspense boundary to stream in late even if it is already loaded by the time that back-pressure flow and in a prerender. Meaning it gets inserted with script.

The effect can be seen in the fixture where if you have large HTML content that can block initial paint (thanks to rel="expect" but also nested Suspense boundaries). Before this fix, the paint would be blocked until the large content loaded. This lets us paint the fallback first in the case that the raw bytes of the content takes a while to download.

You can set it to Infinity to opt-out. E.g. if you want to ensure there's never any scripts. It's always set to Infinity in renderToHTML and the legacy renderToString.

One downside is that if we might choose to outline a boundary, we need to let its fallback complete.

We don't currently discount the size of the fallback but really just consider them additive even though in theory the fallback itself could also add significant size or even more than the content. It should maybe really be considered the delta but that would require us to track the size of the fallback separately which is tricky.

One problem with the current heuristic is that we just consider the size of the boundary content itself down to the next boundary. If you have a lot of small boundaries adding up, it'll never kick in. I intend to address that in a follow up.

Changed files

  • fixtures/ssr/src/components/Chrome.js (modified, +7/-1)
  • fixtures/ssr/src/components/LargeContent.js (added, +243/-0)
  • packages/react-noop-renderer/src/ReactNoopServer.js (modified, +2/-0)
  • packages/react-server/src/ReactFizzServer.js (modified, +54/-12)
  • packages/react-server/src/ReactServerStreamConfigFB.js (modified, +3/-3)

PR #33029: [Fizz] Outline if a boundary would add too many bytes to the next completion

Description (problem / solution / changelog)

Follow up to #33027.

This enhances the heuristic so that we accumulate the size of the currently written boundaries. Starting from the size of the root (minus preamble) for the shell.

This ensures that if you have many small boundaries they don't all continue to get inlined. For example, you can wrap each paragraph in a document in a Suspense boundary to regain document streaming capabilities if that's what you want.

However, one consideration is if it's worth producing a fallback at all. Maybe if it's like null it's free but if it's like a whole alternative page, then it's not. It's possible to have completely useless Suspense boundaries such as when you nest several directly inside each other. So this uses a limit of at least 500 bytes of the content itself for it to be worth outlining at all. It also can't be too small because then for example a long list of paragraphs can never be outlined.

In the fixture I straddle this limit so some paragraphs are too small to be considered. An unfortunate effect of that is that you can end up with some of them not being outlined which means that they appear out of order. SuspenseList is supposed to address that but it's unfortunate.

The limit is still fairly high though so it's unlikely that by default you'd start outlining anything within the viewport at all. I had to reduce the progressiveChunkSize by an order of magnitude in my fixture to try it out properly.

Changed files

  • fixtures/ssr/server/render.js (modified, +2/-2)
  • fixtures/ssr/src/components/Chrome.js (modified, +1/-5)
  • fixtures/ssr/src/components/LargeContent.js (modified, +284/-236)
  • packages/react-server/src/ReactFizzServer.js (modified, +22/-4)

Code Example

npx next info                                                                                                                                                                                                                                                                   main 640174a

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:54:55 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T6031
  Available memory (MB): 36864
  Available CPU cores: 14
Binaries:
  Node: 24.4.0
  npm: 11.4.2
  Yarn: 1.22.22
  pnpm: 10.8.0
Relevant Packages:
  next: 16.2.1-canary.4 // There is a newer canary version (16.2.1-canary.5) available, please upgrade!
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A
There is a newer canary version (16.2.1-canary.5) available, please upgrade!
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/jaslong/next-react-19.2-suspense-boundary-ssr

To Reproduce

Run the dev server and open http://localhost:3000 (app router) or https://localhost:3000/pages (pages router) with devtools open. You can see the server HTML in the network tab of the GET request or with JavaScript disabled.

Current vs. Expected behavior

This repo reproduces a React 19.2 suspense boundary SSR issue in Next.js facebook/react issue #35460. You'll see suspense boundaries containing large HTML content that can't possibly throw/suspend, yet the fallback is rendered in the server HTML.

Provide environment information

npx next info                                                                                                                                                                                                                                                                   main 640174a

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:54:55 PST 2026; root:xnu-12377.91.3~2/RELEASE_ARM64_T6031
  Available memory (MB): 36864
  Available CPU cores: 14
Binaries:
  Node: 24.4.0
  npm: 11.4.2
  Yarn: 1.22.22
  pnpm: 10.8.0
Relevant Packages:
  next: 16.2.1-canary.4 // There is a newer canary version (16.2.1-canary.5) available, please upgrade!
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A
⚠ There is a newer canary version (16.2.1-canary.5) available, please upgrade!
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue

Which area(s) are affected? (Select all that apply)

React

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local)

Additional context

Affected Versions

  • Next.js: 16.2.1-canary.4, 15.5.14 (both app and pages router)
  • React: 19.2.4, 19.2.0 (not 18.3.1, 19.1.5)

Root Cause

React 19.2 introduces a new outlining feature where suspense boundaries with content >12800 bytes will render the fallback for streaming purposes.

Related React PRs:

The 12800 number is the default, but can be configured with the progressiveChunkSize option on renderToReadableStream (docs). The workaround is to set progressiveChunkSize: Infinity.

React or Next.js issue?

Unfortunately, the React team hasn't commented on whether the behavior is intended or not, but at least pure React users are able to use the above described workaround.

Would it make sense for Next.js to expose a way to configure this option?

extent analysis

Fix Plan

To resolve the issue with React 19.2 suspense boundaries in Next.js, you can configure the progressiveChunkSize option.

Here are the steps:

  • Upgrade to the latest Next.js canary version (npm install next@canary) to ensure you have the latest features and fixes.
  • Configure the progressiveChunkSize option when using renderToReadableStream. You can set it to Infinity to prevent the fallback from being rendered for large HTML content.

Example code:

import { renderToReadableStream } from 'react-dom/server';

const html = renderToReadableStream(<App />, {
  progressiveChunkSize: Infinity,
});

Alternatively, you can also configure this option globally in your Next.js application. However, this might require additional setup or patches to the Next.js codebase.

Verification

To verify that the fix worked, run your dev server and open http://localhost:3000 (app router) or https://localhost:3000/pages (pages router) with devtools open. Check the server HTML in the network tab of the GET request or with JavaScript disabled. The suspense boundaries should no longer render the fallback for large HTML content.

Extra Tips

  • Keep an eye on the React and Next.js issue trackers for updates on this behavior and potential fixes.
  • Consider contributing to the Next.js codebase to expose a way to configure the progressiveChunkSize option.
  • Be cautious when setting progressiveChunkSize to Infinity, as it may have performance implications for very large HTML content.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING