Your Node.js Streams Aren’t Backpressuring. They’re Silently Eating Your Memory. – Frontend Masters Blog
This title could be clearer and more informative.Try out Clickbait Shieldfor free (5 uses left this month).
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.
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 StarvationConclusionSort: