What is backpressure?
Backpressure is one of the key principles behind streams in Node.js. It explains how the system prevents overload when one stream produces data faster than another can process it.
In plain words
Backpressure is a mechanism for slowing data transfer down in a chain of streams, so that a Writable Stream doesn't "drown" in data when a Readable Stream is too fast.
Picture a garden hose: if the outlet is clogged, pressure builds up, water flows slower. Streams in Node.js work the same way.
Why it matters
Without a backpressure mechanism:
- a
Writable Streamwould overflow its internal buffer, - the process's memory (RAM) would grow out of control,
- the Event Loop would freeze under the load.
Node.js handles this automatically when .pipe() or pipeline() is used.
How it works
Every stream has an internal buffer, a memory area that temporarily holds chunks.
Writable.write(chunk)returnstrueif the buffer isn't full yet.- It returns
falsewhen reading needs to pause until the buffer frees up.
Once the buffer is ready again, the stream fires a drain event, signaling that writing can continue.
An example (without pipe)
const fs = require('fs');
const readable = fs.createReadStream('bigfile.txt');
const writable = fs.createWriteStream('copy.txt');
readable.on('data', (chunk) => {
const canContinue = writable.write(chunk);
if (!canContinue) {
// The buffer is full, pause reading
readable.pause();
}
});
writable.on('drain', () => {
// The buffer freed up, resume reading
readable.resume();
});
readable.on('end', () => writable.end());Here:
.write()returnsfalsewhenWritablecan't keep up;.pause()and.resume()manually control the reading speed;.drainsignals when to continue.
An example with pipe (automatic)
If .pipe() is used, backpressure is handled automatically:
const fs = require('fs');
fs.createReadStream('bigfile.txt')
.pipe(fs.createWriteStream('copy.txt'));.pipe()tracks when Writable is overloaded,- pauses Readable as needed,
- resumes it once Writable is ready to write again.
How this looks logically
Readable → Writable
If Writable.write() → false
↓
Readable.pause() ← the stream stops
When Writable fires 'drain'
↓
Readable.resume() ← reading resumesAn example via a Transform Stream
The mechanism also works across a chain of several streams:
const { Transform, pipeline } = require('stream');
const fs = require('fs');
const slowTransform = new Transform({
transform(chunk, _, callback) {
setTimeout(() => {
this.push(chunk);
callback();
}, 100); // artificially slow down processing
},
});
pipeline(
fs.createReadStream('input.txt'),
slowTransform,
fs.createWriteStream('output.txt'),
(err) => {
if (err) console.error('Error:', err);
else console.log('Processing finished');
}
);Even if the transformer processes slowly, Node.js automatically regulates the flow, reading never outpaces writing.
The core idea in one sentence
Backpressure is a "smart brake" that prevents buffer overflow, keeping reading and writing speeds in balance.
A quick comparison
| Behavior | Without backpressure | With backpressure |
|---|---|---|
| Streams read without stopping | yes | no |
| Memory grows uncontrollably | yes | no |
| Data gets lost or cut off | possible | no |
| Performance stays stable | no | yes |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.