How do you chain several streams together?
Ways to chain streams
There are two main ways:
- The classic way, via
.pipe() - The modern, safe way, via
stream.pipeline()
1. Chaining via .pipe()
.pipe() is the most basic way to "connect" streams.
It passes one stream's (Readable) output into another's (Writable or Transform) input:
javascript
const fs = require('fs');
const zlib = require('zlib');
fs.createReadStream('input.txt') // Readable
.pipe(zlib.createGzip()) // Transform
.pipe(fs.createWriteStream('output.txt.gz')); // WritableWhat happens:
createReadStream()reads the file in pieces (chunks),createGzip()compresses them on the fly,createWriteStream()writes to the new file.
A chain of several Transform streams
javascript
const fs = require('fs');
const { Transform } = require('stream');
const zlib = require('zlib');
// 1. Convert the text to uppercase
const upper = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
},
});
// 2. Compress the result
const gzip = zlib.createGzip();
fs.createReadStream('input.txt')
.pipe(upper) // Readable → Transform
.pipe(gzip) // Transform → Transform
.pipe(fs.createWriteStream('output.txt.gz')); // Transform → WritableEach
.pipe()returns the next stream, so long chains can be built.
2. Chaining via pipeline()
Since Node.js v10, there's a pipeline() function (in stream)
that does the same thing, but more safely and reliably.
javascript
const { pipeline } = require('stream');
const fs = require('fs');
const zlib = require('zlib');
pipeline(
fs.createReadStream('input.txt'),
zlib.createGzip(),
fs.createWriteStream('output.txt.gz'),
(err) => {
if (err) console.error('Stream error:', err);
else console.log('The file was processed successfully!');
}
);Advantages of pipeline() over .pipe()
| Feature | .pipe() | pipeline() |
|---|---|---|
| Error handling | Manual | Automatic |
| Closing every stream on error | No | Yes |
| A completion callback/promise | No | Yes |
async/await support (stream/promises) | No | Yes |
3. The async variant (stream/promises)
The modern way, with await (Node.js 15+):
javascript
import { pipeline } from 'stream/promises';
import fs from 'fs';
import zlib from 'zlib';
import { Transform } from 'stream';
const upper = new Transform({
transform(chunk, _, cb) {
cb(null, chunk.toString().toUpperCase());
},
});
await pipeline(
fs.createReadStream('input.txt'),
upper,
zlib.createGzip(),
fs.createWriteStream('output.txt.gz')
);
console.log('Every stream finished successfully');A generalized stream-chain diagram
javascript
Readable → Transform → Transform → Writable
↓ ↓ ↓ ↓
Source Filter 1 Filter 2 DestinationEach Transform can:
- compress,
- encrypt,
- filter,
- parse JSON,
- format text,
- log data, and so on.
Key rules when chaining streams
- Order matters, data flows left to right.
- Every
.pipe()returns the next stream, which is what lets you build chains. - Don't forget errors if using
.pipe()withoutpipeline():
javascript
stream.on('error', console.error);- Use
pipeline()in production, it closes everything on its own if something fails.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.