# Node.js Streams Cheat Sheet
_Backpressure, pipeline and why you should stop using .pipe()_
Streams process data without holding it in memory. They are also where Node applications leak, hang and lose errors — almost always for the same three reasons.
> Difficulty: intermediate  
> Version: 1.0  
> Updated: 2025-06-06  
> Categories: Node.js  
> Tags: Streaming

Source: https://invitationbuddy.com/cheat-sheet/nodejs-streams-cheat-sheet

---

## Types
| Type | Does | Example |
| --- | --- | --- |
| `Readable` | Produces data  fs.createReadStream, an HTTP request |
| `Writable` | Consumes data  fs.createWriteStream, an HTTP response |
| `Duplex` | Both, independently  A TCP socket |
| `Transform` | Both, output derived from input  zlib.createGzip |

## Composition
| Pattern | Note |
| --- | --- |
| `await pipeline(src, transform, dest)` | The right default — propagates errors and cleans up |
| `src.pipe(dest)` | Does NOT forward errors and leaks on failure |
| `for await (const chunk of readable)` | Async iteration; honours backpressure automatically |
| `Readable.from(asyncGenerator())` | Turn any async generator into a stream |
| `stream.destroy(err)` | Tear down and propagate |

## Backpressure
writable.write() returns false when its buffer is full. Ignoring that return value is how a fast reader and a slow writer turn into unbounded memory growth — the data has to go somewhere, and it goes into RAM. pipeline() and for-await both handle this for you; a hand-rolled loop must wait for the "drain" event itself.

## Code examples
### pipeline() with a transform
The composition that propagates errors and cleans up. .pipe() does neither.
```javascript
import { pipeline } from 'node:stream/promises';
import { Transform } from 'node:stream';
import { createReadStream, createWriteStream } from 'node:fs';
import { createGzip } from 'node:zlib';

const upper = new Transform({
  transform(chunk, _enc, cb) {
    cb(null, chunk.toString().toUpperCase());
  },
});

try {
  await pipeline(
    createReadStream('in.txt'),
    upper,
    createGzip(),
    createWriteStream('out.txt.gz'),
  );
  console.log('done');
} catch (err) {
  console.error('stream failed:', err);   // reachable, unlike with .pipe()
}
```

## FAQs
**Why should I stop using .pipe()?**
It does not forward errors and does not clean up on failure, so a broken destination leaks the source handle and your catch block never runs. pipeline() fixes both.

**What is backpressure, practically?**
write() returning false means the buffer is full. Ignoring it means the unread data piles up in memory. pipeline() and for-await both handle it; a hand-rolled loop must wait for "drain".

---
_Generated from https://invitationbuddy.com/cheat-sheet/nodejs-streams-cheat-sheet_
