Skip to content

Writable Streams

A Writable is a stream to which data can be written. Node’s built-in examples include fs.createWriteStream (writing a file), process.stdout (terminal output), and HTTP response objects. You can also create custom writables by extending Writable and implementing the _write method.

The two primary methods on a Writable are:

  • writable.write(chunk[, encoding][, callback]) — writes a chunk of data. Returns true if the internal buffer is below the high-water mark, false if the destination cannot keep up (backpressure signal).
  • writable.end([chunk][, callback]) — signals that no more data will be written. Optionally writes one final chunk. Triggers the finish event once all data has been flushed.
const fs = require('node:fs');
const dest = fs.createWriteStream('./output.txt');
dest.write('first line\n');
dest.write('second line\n');
dest.end('last line\n', function() {
console.log('all data flushed');
});

After end() is called and all pending data has been flushed to the underlying system, the stream emits finish. This is the correct moment to know writing is truly complete:

dest.on('finish', function() {
console.log('write complete');
});

write() returns a boolean. When it returns false, the internal buffer is full — you must stop writing and wait for the drain event before writing more. Ignoring this causes unbounded memory growth as buffered chunks accumulate.

function writeWithDrain(writable, chunks) {
var i = 0;
function next() {
while (i < chunks.length) {
var ok = writable.write(chunks[i]);
i++;
if (!ok) {
// buffer full — wait for drain before continuing
writable.once('drain', next);
return;
}
}
writable.end();
}
next();
}

This is the manual pattern that pipe and pipeline handle for you automatically. Understanding it explains why those higher-level APIs exist.

The demo creates a custom Writable that logs each chunk to the console, simulating a slow sink. It then writes three chunks and closes the stream.

Node.js

Needs the Node.js runtime — open in StackBlitz to run.

What does writable.write() return when the internal buffer is full?
Which event fires after writable.end() is called and all data has been flushed?
What is the correct action when writable.write() returns false?