Skip to the solution
EasyPhone Screen6 min read

What are stream piping and the .pipe() method in Node.js?

978 views

The problem

Question presented to candidate: "You need to copy data from a readable source directly to a writable destination β€” a file to an HTTP response, for instance. What does .pipe() actually do, and why not just manually forward each chunk yourself?"

What a strong answer should cover:

  • .pipe() connects a Readable stream's output directly to a Writable stream's input: every chunk the readable produces is automatically written to the writable, without manually wiring up 'data' event listeners and calling .write() yourself.
  • πŸ“Œ It automatically handles backpressure: if the destination writable is slower than the source readable, .pipe() automatically pauses reading from the source until the destination signals it can accept more β€” manually forwarding 'data' events yourself does not do this for free.
  • stream.pipe() returns the destination stream, which is what enables chaining: source.pipe(transform1).pipe(transform2).pipe(destination), passing data through successive transform steps.
  • .pipe()'s well-known limitation, covered fully in its own dedicated question, is incomplete error propagation and cleanup: an error on the source does not automatically destroy the destination, which can leak open file handles/sockets β€” stream.pipeline() (Node's modern replacement) fixes exactly this.
  • A concrete, common real-world use: fs.createReadStream(path).pipe(res) inside an HTTP handler streams a file directly to the client without ever loading the whole file into memory β€” connecting the file-system-read question and the readFile-vs-createReadStream question to this one.
  • A precise answer names .pipe() as the original, still-common mechanism, while pointing to stream.pipeline() as the currently recommended choice for anything beyond the simplest, single-hop, already-correctly-error-handled case.

Clarifying questions expected:

  • "Is proper error handling and cleanup across the whole chain a requirement here?" β€” if so, stream.pipeline() is the better answer than raw .pipe().
  • "Is this a single hop (source to destination) or a multi-step transform chain?" β€” .pipe()'s chaining return value matters more for the latter.

Code / implementation expected: Yes β€” a real, working .pipe() call actually delivering data end to end is the concrete, convincing part of the answer.

  • streams
  • file-system
  • pipes

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read Β· 10 sections

Read the code

JavaScriptA real .pipe() call delivering exact source data to a custom destination, end to end
const { Readable, Writable } = require("stream");

const src = Readable.from(["chunk1-", "chunk2-", "chunk3"]);
let received = "";
const dest = new Writable({
  write(chunk, enc, cb) {
    received += chunk;
    cb(); // signals "ready for the next chunk" β€” this is what enables backpressure
  },
});

src.pipe(dest);
dest.on("finish", () => console.log("received via pipe:", received));
// received via pipe: chunk1-chunk2-chunk3

// A common real use β€” streaming a file directly to an HTTP response:
// fs.createReadStream("./large-file.zip").pipe(res);

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 6 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextEasy

What does the Node.js --watch flag do and how does it replace nodemon?

Continue