Working with Streams

1. Creating Readable Streams (fs.createReadStream)

Example

import { createReadStream } from "node:fs";
const rs = createReadStream("big.csv", { encoding: "utf8", highWaterMark: 64 * 1024 });
for await (const chunk of rs) process(chunk);
ModeBehavior
FlowingPushed via data event
PausedPulled via read()

2. Creating Writable Streams (fs.createWriteStream)

APIUse
ws.write(chunk)Returns false when buffer full
ws.end(chunk?)Finish stream
Event drainResume writing
Event finishAll data flushed

3. Using Transform Streams (stream.Transform)

Example: gzip on the fly

import { pipeline } from "node:stream/promises";
import { createReadStream, createWriteStream } from "node:fs";
import { createGzip } from "node:zlib";
await pipeline(createReadStream("file.txt"), createGzip(), createWriteStream("file.txt.gz"));

4. Using Duplex Streams

TypeExamples
DuplexTCP socket, ZLib stream
Transform (subclass)Hash, Compression, Crypto cipher

5. Handling Stream Events

EventStream Type
dataReadable (flowing)
endReadable
readableReadable (paused)
drainWritable
finishWritable
closeBoth
errorBoth

6. Piping Streams

Example: pipeline (preferred)

import { pipeline } from "node:stream/promises";
await pipeline(src, transform, dest);
Warning: Avoid raw .pipe() chains — they don't propagate errors. Use pipeline.

7. Controlling Stream Flow

MethodEffect
stream.pause()Stop emitting data
stream.resume()Resume
stream.read(n)Pull bytes (paused mode)

8. Using Backpressure

Backpressure

write() returns false → producer should pause
                       ↓
            wait for "drain" event
                       ↓
              resume writing
      
ToolHandles BP
pipeline✅ automatically
Manual pipeYes, but no error propagation
Manual write loopMust check return value

9. Working with Object Mode

Example

import { Transform } from "node:stream";
const toUpper = new Transform({
  objectMode: true,
  transform(obj, _, cb) { cb(null, { ...obj, name: obj.name.toUpperCase() }); }
});

10. Using stream.Readable.from() Method

SourceResult
IterableReadable.from([1,2,3])
Async iterableReadable.from(asyncGen())
String / BufferSingle chunk stream

11. Consuming Streams with Async Iterators

Example

for await (const chunk of readable) {
  process(chunk);
}

12. Understanding Highwater Mark

DefaultValue
Byte streams16 KB
Object mode16 objects
Tuning upFewer reads, more memory