Skip to content

Node.js 26: inline Flight data is split into one <script> per chunk on 16.4.x (~130× more scripts, 4× gzip bytes) — fixed on canary by #100142 #101343

Open

Description

@v-dev-cl

Link to the code that reproduces this issue

https://github.com/v-dev-cl/next-node26-flight-repro

To Reproduce

  1. npm install && npm run build (any Node version).
  2. Start the build with Node 24.x: node node_modules/next/dist/bin/next start -p 3100, then in another terminal run node measure.mjs http://127.0.0.1:3100/ 7.
  3. Stop the server, start the same build with Node 26.x, and run measure.mjs again.

measure.mjs fetches the page with gzip and prints medians of inline Flight scripts, response chunks, gzip bytes and request time.

Current vs. Expected behavior

Current: on Node 26, Next 16.4.5 splits the inline Flight data into one <script>self.__next_f.push(…)</script> per chunk React buffered. Each script is a separate response write and gzip flush.

inline Flight scripts response chunks gzip bytes median request
next 16.4.5 · Node 24.22.2 3 4 10,771 19.2 ms
next 16.4.5 · Node 26.13.0 407 411 47,301 26.1 ms
next 16.5.0-canary.43 · Node 26.13.0 3 5 10,786 17.4 ms

Expected: the same output on Node 26 as on Node 24.

Cause. Node.js 26.0.0 changed Readable#read(): called with no size, it returns one buffered chunk instead of everything buffered (nodejs/node#60441, semver-major; the Node docs still describe the old behaviour, see nodejs/node#67323). pullFlightData in app-render loops on dataStream.read() and wraps each result in its own script. So the number of scripts now follows the number of chunks React wrote. Long strings (over ~1.3 K characters) are their own chunks.

Seen on a real app. We compared Node 24.22.2 and 26.13.0 on the same App Router build: 5 rounds of 600 requests at concurrency 8, with a Node 24 vs Node 24 control run to measure noise. On Node 26, p95 was +28 % and p99 +35 % on average, outside the noise band in 5 of 5 rounds. Our heaviest page went from 5 to 106 inline scripts, with 67 % more gzip bytes. Changing that one call to dataStream.read(dataStream.readableLength || undefined) brought Node 26 back within noise. That is the migration hint from nodejs/node#60441.

Already fixed on canary. #100142 ("Build the inline Flight script from React's strings instead of re-encoding them", merged 2026-10-24) switches the Flight stream to object mode and batches every buffered chunk into one script. 16.5.0-canary.43 does not reproduce (row 3 above).

Request. Could that batching, or the one-line read(readableLength) change, go out in a 16.4.x patch release? Node 26 became LTS with 26.13.0 (2026-10-28), so more apps on 16.4 will hit this as they upgrade.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Available memory (MB): 128534
  Available CPU cores: 20
Binaries:
  Node: 26.13.0
  npm: 11.20.0
Relevant Packages:
  next: 16.4.5 // Latest available version is detected (16.4.5).
  eslint-config-next: N/A
  react: 19.3.1
  react-dom: 19.3.1
  typescript: N/A
Next.js Config:
  output: N/A

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

Performance, Loading UI and Streaming, Runtime

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

next start (local), Other (Deployed)

Additional context

Node 24.x is not affected. The repro uses plain JSX, with no TypeScript or config, and the same build on both runtimes.

Activity

  1. added
    Loading UI and StreamingRelated to loading UI (loading.tsx) and streaming.
    PerformanceAnything with regards to Next.js performance.
    RuntimeRelated to Node.js or Edge Runtime with Next.js.
    on Nov 7, 2026
  2. ruturaaj16 commented on Nov 7, 2026

    @ruturaaj16

    @toolmantim can I work on this issue, can you assign it to me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Loading UI and StreamingRelated to loading UI (loading.tsx) and streaming.PerformanceAnything with regards to Next.js performance.RuntimeRelated to Node.js or Edge Runtime with Next.js.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions