Web Streams

Web Streams and Conversion Helpers

Node ships two stream implementations. node:stream is the original, event-based one used so far. node:stream/web implements the WHATWG Streams standard — ReadableStream, WritableStream, TransformStream and the queuing strategies — the same objects a browser exposes, and globals in Node. The Node documentation marks it Stability 2 – Stable; it left experimental status in Node 21. It signals backpressure through promises such as writer.ready, not a false return and a drain event.

You meet both either way: fetch() response bodies, Blob.stream(), CompressionStream and TextDecoderStream are Web Streams, while fs, net, http and zlib give Node streams. Six conversion helpers bridge them, stable since Node 24.0.0 and 22.17.0.

Converting between Node streams and Web StreamsJavaScript
import { text } from 'node:stream/consumers';
const upper = new TransformStream({ transform: (c, ctl) => ctl.enqueue(c.toUpperCase()) });
const src = ReadableStream.from(['alpha ', 'beta']);
console.log(await text(Readable.fromWeb(src.pipeThrough(upper))));   // Web -> Node
await pipeline(                                   // both kinds in one pipeline
  Readable.from(['web streams ', 'and node streams interop']), new TextEncoderStream(),
  new CompressionStream('gzip'), Writable.toWeb(createWriteStream('interop.gz')),
);
Output
ALPHA BETA

Readable.toWeb(nodeReadable) goes the other way, and node:stream/consumers (text, json, buffer, arrayBuffer, blob) collects either kind into a value, for payloads small enough to hold in memory.

Prefer Node streams for server-side plumbing and Web Streams for code that must also run in a browser or edge runtime — as a Next.js 10,514 route handler streaming a response does (Next.js).