What is a Transform stream?
A Transform Stream is a special kind of Node.js stream that is both Readable and Writable,
but unlike a plain Duplex, it transforms the data passing through it.
In other words: a Transform Stream = a Duplex Stream + data transformation.
The concept
A Transform Stream takes input data → processes it → outputs a modified result.
It's used when you need to process a data stream on the fly, without waiting for it to end.
Examples of built-in Transform Streams
| Module | Example | Description |
|---|---|---|
zlib | zlib.createGzip() / zlib.createGunzip() | Compressing and decompressing data |
crypto | crypto.createCipheriv() / createDecipheriv() | Encryption/decryption |
stream | new stream.Transform() | Building your own transform stream |
readline | Line-by-line text transformations |
A simple analogy
Picture a conveyor belt:
- a stream of lines goes in,
- the stream transforms them (for example, calls
toUpperCase()), - and outputs the modified data.
A custom Transform Stream example
javascript
const { Transform } = require('stream');
class UpperCaseTransform extends Transform {
constructor(options) {
super(options);
}
_transform(chunk, encoding, callback) {
const transformed = chunk.toString().toUpperCase();
this.push(transformed); // pass the result along
callback(); // signal that processing is done
}
}
const upperCase = new UpperCaseTransform();
process.stdin.pipe(upperCase).pipe(process.stdout);Here:
process.stdinis the input stream (Readable),upperCaseis our Transform stream (modifies the data),process.stdoutis the output stream (Writable).
Anything you type into the console prints back in uppercase.
The main Transform Stream methods
| Method | Description |
|---|---|
_transform(chunk, encoding, callback) | The main method, transforms the input data |
_flush(callback) | Called once the input stream ends, lets you "push out" any leftover data |
.push(data) | Passes processed data to the output stream |
An example with _flush()
javascript
class JSONLinesTransform extends Transform {
constructor() {
super({ readableObjectMode: true });
this.buffer = '';
}
_transform(chunk, encoding, callback) {
this.buffer += chunk.toString();
let lines = this.buffer.split('\n');
this.buffer = lines.pop(); // keep the last, incomplete line
for (const line of lines) {
if (line.trim()) {
this.push(JSON.parse(line));
}
}
callback();
}
_flush(callback) {
if (this.buffer.trim()) {
this.push(JSON.parse(this.buffer));
}
callback();
}
}This stream:
- reads JSON lines one by one,
- turns them into JavaScript objects,
- and passes them along as a stream of objects.
Typical Transform Stream use cases
| Task | Example |
|---|---|
| Compressing files | fs.createReadStream('file.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('file.gz')) |
| Encryption | fs.createReadStream('data').pipe(crypto.createCipheriv(...)).pipe(fs.createWriteStream('data.enc')) |
| Formatting data | JSON → CSV, XML → JSON, and so on |
| Logging / filtering / debouncing | Streaming transformation of logs, HTTP requests, sensor data |
The difference between Duplex and Transform
| Property | Duplex | Transform |
|---|---|---|
| Reading and writing | Yes | Yes |
| Transforms data | No | Yes |
| Input and output are linked | No | Yes |
| Example | A TCP socket | gzip, a cipher, a JSON parser |
Advantages of Transform Streams
- Asynchronous processing on the fly
- Memory savings, no need to hold the whole file in RAM
- Simple composition (
pipe()chains) - Easy to extend, custom transformers are simple to write
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.