Search across all documentation pages
stream/promises.pipeline connects Readable → Transform → Writable with correct error propagation, stream destruction on failure, and a Promise API suited to async/await handlers.
import { pipeline } from 'node:stream/promises';
import { createReadStream, createWriteStream } from 'node:fs';
import { createGzip } from 'node:zlib';
await pipeline(
createReadStream('input.log'),
createGzip(),
createWriteStream('input.log.gz'),
);When to reach for this:
.on('error') spaghetti on manual pipesimport { pipeline } from 'node:stream/promises';
import { createReadStream } from 'node:fs';
import { createServer } from 'node:http';
import { Transform } from 'node:stream';
import { createGzip } from 'node:zlib';
const lineCount = new
What this demonstrates:
pipeline accepts Writable HTTP res as final sinkheadersSent require ending response without second status lineawait integrates with try/catch like any async I/Opipeline destroys participating streams with the error.end.node:stream - Promise variant preferred in async code.| Feature | pipeline | manual pipe |
|---|---|---|
| Error forward | Yes | Manual |
| Destroy on fail | Yes | Manual |
| Promise API | Yes | No |
| AbortSignal | Yes | Manual |
import { pipeline } from 'node:stream/promises';
import type { Readable, Writable } from 'node:stream';
export async function safePump(
source: Readable,
sink: Writable,
signal?: AbortSignal,
)
writeHead before pipeline to sink response. Fix: set headers first.req.on('aborted') optionally. Fix: pass AbortSignal linked to request._flush for trailing buffered data.| Alternative | Use When | Don't Use When |
|---|---|---|
finished + manual destroy | Legacy streams code | Greenfield |
pump (npm) | Older Node versions | Node 24 has native pipeline |
| Buffer entire payload | Tiny files < 1 MB | Large downloads |
Web pipeThrough | fetch Web Streams | node:fs sources |
Yes - on success or failure participating streams are destroyed/ended appropriately.
Yes - variadic arguments: pipeline(a, b, c, d, sink).
Pass { signal: abortController.signal } option in Node 24 pipeline.
ENOENT on missing file, ECONNRESET on client disconnect, zlib errors on corrupt gzip.
Legacy callback API - Promise version preferred in async handlers.
Yes - data flows left to right through each Transform.
All streams in chain must agree on object vs byte mode (with converting Transform).
PassThrough tap stream in middle counting chunk.length.
Same pattern - await pipeline(source, res) inside async route with error wrapper.
Use reply.send(stream) or pipeline into raw response per Fastify 5 docs for fine control.
Use stream/consumers.buffer or Writable that collects chunks in memory for assertions.
Inherited from stream semantics - pipeline does not remove need for sensible highWaterMark.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.