Readable, writable and duplex streams in Node.js

Updated

A stream in Node is simply a sequence of bytes. A stream contains a buffer of bytes, and this buffer has a zero or greater length. In Node, streams are objects representing data flows that can be written to and read from asynchronously. The Stream interface is an abstract interface. An abstract interface function is like a blueprint which tells the user what kinds of data types or functions need to be implemented while creating an instance of Stream. Example, a Readable stream implementation is required to implement a public read method which delegates to the interface’s internal _read method.

In general, all stream implementations should follow these guidelines: 1. As long as data exists to send, write to a stream until that operation returns false, at which point the implementation should wait for a drain event, indicating that the buffered stream data has emptied. 2. Continue to call read until a null value is received, at which point wait for a readable event prior to resuming reads. 3. Several Node I/O modules are implemented as streams. Network sockets, file readers and writers, stdin and stdout, zlib, and so on. Similarly, when implementing a readable data source, or data reader, one should implement that interface as a Stream interface.

Readable Stream: Streams producing data that another process may have an interest in are implemented using a Readable stream. A Readable stream saves the implementer the work of managing the read queue, handling the emitting of data events, etc. Readable base class takes 3 attributes: i) encoding: Decode buffers into the specified encoding, defaulting to UTF-8. ii) highWaterMark: Number of bytes to keep in the internal buffer before ceasing to read from the data source. The default is 16 KB. iii) objectMode: Tell the stream to behave as a stream of objects instead of a stream of bytes, such as a stream of JSON objects instead of the bytes in a file. Default false.

var Feed = function(channel) 
{    
var readable = new stream.Readable(
{        
    encoding : "utf8"    
});    
var news = ["Big Win!", "Stocks Down!","Actor Sad!"];    
readable._read = function() 
{        
    if(news.length) 
    {            
        return readable.push(news.shift() + "\n");        
    }        
    readable.push(null);    
};    
return readable; 
}

Writable Stream: A Writable stream is responsible for accepting some value and writing that data to a destination. Writable base class takes attributes: i) highWaterMark: The maximum number of bytes the stream’s buffer will accept prior to returning false on writes. Default is 16 KB. ii) decodeStrings: Whether to convert strings into buffers before writing. Default is true. Example, here we write 100 bytes to stdout:

var stream = require('stream'); 
var writable = new stream.Writable(
{    
    decodeStrings: false 
}); 
writable._write = function(chunk, encoding, callback) 
{    
    console.log(chunk);    
    callback(); 
} 
var w = writable.write(Buffer.alloc(100)); 
writable.end(); 
console.log(w); // Will be `true`

Duplex Stream: A duplex stream is both readable and writeable. For instance, a TCP server created in Node exposes a socket that can be both read from and written to:

var stream = require("stream"); 
var net = require("net"); 
net
.createServer(
function(socket) 
{    
    socket.write("Go ahead and type something!");    
    socket.on("readable", function() 
    {        
        process.stdout.write(this.read() || "")    
    }); 
}).listen(8080);

When the above code is executed, this code will create a TCP server that can be connected via Telnet: telnet 127.0.0.1 8080. Upon connection, the connecting terminal will print out ‘Go ahead and type something!’—writing to the socket. Any text entered in the connecting terminal will be echoed to the stdout of the terminal running the TCP server.

Comment
Next tutorial
Mithlesh Upadhyay Published 7 Nov 2026 · 3 min read

Mithlesh Upadhyay is a Computer Science and AI expert from Madhya Pradesh with strong academic background (BE in CSE and M.Tech in AI) and over six years of experience in technical content development. He has contributed tech articles, led teams, and worked in Full Stack Development and Data Science. He founded the w3colleges.org portal for learning resources.

Related tutorials

  • URLSearchParams.append() method in Node.js

    The urlSearchParams.append() is an inbuilt application programming interface of class URLSearchParams with in url module which is used to append the associate argument of name to value in…

    2 min read
  • Strict mode in JavaScript

    For a long time, JavaScript had no compatibility issues because in every new version release old functionality were not changing. But it was not good as if there…

    2 min read
  • Code structure in JavaScript: Semicolon and Comment

    Semicolons and Comments are buidling blocks of code. Semicolons We can have as many statements in our code as we want. Statements can be separated with a semicolon.…

    3 min read
  • Hello, world! in JavaScript

    In this part of the tutorial, we will learn on core JavaScript. We need working environment o run our scripts. We will use either IDE or browser to…

    4 min read
  • Developer console in web browsers

    Code is prone to errors, and as a human, it’s natural to make mistakes. In the browser, errors are not visible to users by default, which makes it…

    2 min read
  • JavaScript Manuals and specifications

    This is a tutorial designed to help you learn the language gradually, but you’ll eventually need additional resources. 1. Specification The ECMA-262 specification is the most detailed and…

    2 min read