Question presented to candidate: "You need to serve a 2GB video file from an HTTP endpoint. Would you use fs.readFile or fs.createReadStream, and what specifically goes wrong with the other choice?"
What a strong answer should cover:
fs.readFile(andfs.promises.readFile) reads the entire file into memory and delivers it as a single callback/Promise resolution carrying one completeBuffer— simple to use, but memory usage scales directly with file size.fs.createReadStreamreads the file incrementally, delivering it across many smaller chunks (sized byhighWaterMark, default 64KB) via'data'events (or async iteration, or piped directly to a writable) — memory usage stays roughly constant regardless of total file size.- 📌 The concrete, measured difference: the identical 20MB file arrived as one
readFilecallback carrying the full 20MB buffer, versus 320 separate'data'events fromcreateReadStreamwith a 64KBhighWaterMark— the same total bytes, delivered in a fundamentally different shape. - The practical rule:
readFileis fine for files small relative to available memory where the whole content is needed at once anyway (a config file, a small template).createReadStream— usually piped directly to an HTTP response or another writable — is correct for large files, especially ones served over a network, where loading the entire file into memory first is wasteful or outright impossible at scale. - Streaming also enables starting the response before the whole file is read — a client receiving a large file over
createReadStream.pipe(res)` starts receiving bytes almost immediately, rather than waiting for the entire file to load into memory first. - A precise answer connects this to backpressure: a stream naturally slows its internal reads to match how fast the destination can consume data (covered fully in the dedicated
stream.pipeline()/backpressure questions);readFilehas no equivalent concept — it either succeeds with the whole buffer or fails entirely.
Clarifying questions expected:
- "How large is the file relative to the process's available memory, and how many concurrent requests need to read it?" — this is the actual deciding factor, not a blanket rule.
- "Does the whole file need to be in memory at once for further synchronous processing, or can it be handled chunk by chunk?" — decides whether streaming is even applicable to the use case.
Code / implementation expected: Yes — the measured chunk/callback count difference for the identical file is the concrete, convincing part of the answer.