Suggest an editImprove this articleRefine the answer for “How do you chain several streams together?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)The classic way is `.pipe()`, which returns the next stream, so calls can be chained (`readable.pipe(transform).pipe(writable)`); the modern, safer way is `stream.pipeline()`, which handles errors automatically and supports `await` via `stream/promises`. **Key point:** if you use `.pipe()` without `pipeline()`, always subscribe to `stream.on('error', ...)` on every stream - otherwise an unhandled error crashes the process.Shown above the full answer for quick recall.Answer (EN)Image## Ways to chain streams There are **two main ways**: 1. **The classic way, via** `.pipe()` 2. **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')); // Writable ``` **What 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 → Writable ``` > Each `.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 Destination ``` Each `Transform` can: - compress, - encrypt, - filter, - parse JSON, - format text, - log data, and so on. ## Key rules when chaining streams 1. **Order matters**, data flows left to right. 2. **Every** `.pipe()` **returns the next stream**, which is what lets you build chains. 3. **Don't forget errors** if using `.pipe()` without `pipeline()`: ```javascript stream.on('error', console.error); ``` 4. **Use** `pipeline()` **in production**, it closes everything on its own if something fails.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.