Backpressure

Writable Streams and Backpressure

writable.write(chunk) never blocks and never rejects a chunk. It returns a boolean: true means the queue is still below the highWaterMark, false that you are filling memory faster than the destination drains it. Ignoring that return value turns a streaming program back into a buffering one: the data still arrives, but it queues in the process until the heap runs out.

Chunks flow left to right; the false/drain signal flows back
Chunks flow left to right; the false/drain signal flows back
Watching write() report backpressureJavaScript
import { once } from 'node:events';
const slow = new Writable({ highWaterMark: 4096, write(c, enc, cb) { setTimeout(cb, 5); } });
const chunk = Buffer.alloc(1024, 0x41); let accepted = 0, drains = 0;
for (let i = 0; i < 200; i++) {
  const ok = slow.write(chunk);
  if (i < 4) console.log(`write ${i + 1}: returned ${ok}, ${slow.writableLength} B queued`);
  if (ok) accepted++; else { drains++; await once(slow, 'drain'); }
}
slow.end();
console.log(`${accepted} writes buffered immediately, ${drains} waits for drain`);
Output
write 1: returned true, 1024 B queued
write 2: returned true, 2048 B queued
write 3: returned true, 3072 B queued
write 4: returned false, 4096 B queued
150 writes buffered immediately, 50 waits for drain

Four 1 KB chunks fill a 4 KB queue, so the pattern repeats: three fast writes, then one await once(stream, 'drain') — the state writableNeedDrain also reports. Memory stays at 4 KB however long the loop runs. end() flushes and emits finish, meaning the last _write callback fired, not that the bytes reached the disk — call fsync if durability matters. To forward one stream into another, do not write this loop: pipeline implements it correctly, errors included.