Node.js streams don't automatically prevent memory exhaustion — backpressure is a cooperative protocol that producers must actively respect. The core issue: `.write()` returns `false` when the internal buffer exceeds `highWaterMark`, but nothing forces you to honor that signal. Ignoring it causes unbounded heap growth that only manifests under large datasets. Key pitfalls covered include: the `highWaterMark` advisory threshold (bumped 4x in Node.js 22), `objectMode` counting objects not bytes, Transform streams with independent readable/writable buffers, `.pipe()` silently swallowing errors and leaking file descriptors, and `async/await` pacing reads but not writes. The fix for write loops is checking the `.write()` return value and awaiting the `drain` event. `pipeline()` from `node:stream/promises` replaces `.pipe()` with proper error propagation. Finally, correctly implementing backpressure can expose a secondary problem: database connection pool starvation when slow clients hold cursors open, requiring query timeouts, dedicated worker pools, or queue-based offloading for large exports.

19m read timeFrom frontendmasters.com
Post cover image
Table of contents
What You Think Streams Do vs. What They Actually DoThe highWaterMark LieWhy .pipe() Is Quietly Ruining Your Production ServicesAsync/Await Won’t Save YouThe Hidden Cost of Pausing: Connection StarvationConclusion

Sort: