DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question
  1. Home
  2. Articles
  3. Frontend Engineering
  4. Node.js Streams: Processing Large Data Efficiently
XLinkedInReddit
MediumFrontend Engineering

Node.js Streams: Processing Large Data Efficiently

D
DevPrep Team
February 10, 2026·1 min read·0
Table of Contents
  • Why Streams?
  • Stream Types
  • The pipe() Method
  • Transform Streams
  • Modern Async Iteration
  • Backpressure

Streams let you process data piece by piece instead of loading everything into memory. Essential for handling large files and real-time data.

Why Streams?

// Bad: loads entire file into memory
const data = fs.readFileSync("huge-file.csv"); // 2GB in memory!

// Good: processes chunk by chunk
const stream = fs.createReadStream("huge-file.csv");
stream.on("data", (chunk) => processChunk(chunk)); // ~64KB at a time

Stream Types

  1. Readable: Source of data (fs.createReadStream, http.IncomingMessage)
  2. Writable: Destination (fs.createWriteStream, http.ServerResponse)
  3. Transform: Modify data passing through (zlib.createGzip)
  4. Duplex: Both readable and writable (net.Socket)

The pipe() Method

// Compress a file
fs.createReadStream("input.txt")
  .pipe(zlib.createGzip())
  .pipe(fs.createWriteStream("input.txt.gz"));

// HTTP response streaming
app.get("/large-file", (req, res) => {
  const stream = fs.createReadStream("huge.csv");
  res.setHeader("Content-Type", "text/csv");
  stream.pipe(res);
});

Transform Streams

const { Transform } = require("stream");

const upperCase = new Transform({
  transform(chunk, encoding, callback) {
    this.push(chunk.toString().toUpperCase());
    callback();
  }
});

process.stdin.pipe(upperCase).pipe(process.stdout);

Modern Async Iteration

async function processCSV(filePath) {
  const stream = fs.createReadStream(filePath, { encoding: "utf8" });
  let lineBuffer = "";
  
  for await (const chunk of stream) {
    lineBuffer += chunk;
    const lines = lineBuffer.split("\\n");
    lineBuffer = lines.pop(); // Keep incomplete line
    
    for (const line of lines) {
      await processLine(line);
    }
  }
}

Backpressure

When the writable stream can't keep up with the readable stream, backpressure builds up. pipe() handles this automatically. If using manual events, check the return value of write() and wait for the drain event.

Related Articles

MediumFrontend Engineering

System Design #12: Design a Multi-Step Form Wizard

7 min read
MediumFrontend Engineering

Mastering Senior-Level JavaScript Interview Concepts

2 min read
MediumFrontend Engineering

System Design #9: Design a Collaborative Text Editor

9 min read

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Table of Contents

  • Why Streams?
  • Stream Types
  • The pipe() Method
  • Transform Streams
  • Modern Async Iteration
  • Backpressure

Series

View all Frontend Engineering articles →

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.