How to create readable streams in Node.js
Creating custom readable streams in Node.js enables dynamic data generation and efficient data production for various applications and data sources.
With over 25 years of experience in software development and as the creator of CoreUI, I’ve built numerous readable streams for API data feeds, database cursors, and real-time data generation.
From my expertise, the most reliable approach is extending the Readable class and implementing the _read() method to control data production.
This pattern provides complete control over data flow timing, batching, and source management for scalable data streaming applications.
Extend the Readable class and implement the _read() method to create custom data-producing streams.
const { Readable } = require('stream')
class NumberStream extends Readable {
constructor(options = {}) {
super(options)
this.current = 1
this.max = options.max || 100
}
_read() {
if (this.current <= this.max) {
this.push(`Number: ${this.current}\n`)
this.current++
} else {
this.push(null) // Signal end of stream
}
}
}
const numberStream = new NumberStream({ max: 10 })
numberStream.on('data', chunk => console.log(chunk.toString()))
Here the NumberStream class extends Readable and generates sequential numbers. The _read() method is called when the stream needs more data, using this.push() to add data to the internal buffer. Pushing null signals the end of the stream. The constructor accepts options for customization. This pattern is ideal for generating data from databases, APIs, or computational processes without blocking the event loop.
Best Practice Note:
This is the same approach we use in CoreUI data services for streaming large dataset exports, real-time analytics feeds, and paginated API responses. Always implement backpressure handling and consider using async generators for simpler readable stream creation in modern Node.js versions.



