Skip to main content

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

ModuleExampleDescription
zlibzlib.createGzip() / zlib.createGunzip()Compressing and decompressing data
cryptocrypto.createCipheriv() / createDecipheriv()Encryption/decryption
streamnew stream.Transform()Building your own transform stream
readlineLine-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.stdin is the input stream (Readable),
  • upperCase is our Transform stream (modifies the data),
  • process.stdout is the output stream (Writable).

Anything you type into the console prints back in uppercase.

The main Transform Stream methods

MethodDescription
_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

TaskExample
Compressing filesfs.createReadStream('file.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('file.gz'))
Encryptionfs.createReadStream('data').pipe(crypto.createCipheriv(...)).pipe(fs.createWriteStream('data.enc'))
Formatting dataJSON → CSV, XML → JSON, and so on
Logging / filtering / debouncingStreaming transformation of logs, HTTP requests, sensor data

The difference between Duplex and Transform

PropertyDuplexTransform
Reading and writingYesYes
Transforms dataNoYes
Input and output are linkedNoYes
ExampleA TCP socketgzip, 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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.