Data Handling in Node.js
Data Handling in Node.js Interview with follow-up questions
1. What is the difference between readFile and createReadStream in Node.js?
Both read files, but differ in how the data is delivered — and the source's claim that readFile is synchronous is wrong, so correct it:
fs.readFile(andfs.promises.readFile) is asynchronous and non-blocking, but it reads the entire file into memory at once, returning a Buffer/string when done. Simple, but a large file can spike memory or exceed buffer limits. (The truly blocking variant isfs.readFileSync.)fs.createReadStreamreturns a readable stream that delivers the file in chunks as they're read. Memory stays roughly constant regardless of file size, and you can start processing/piping before the whole file is loaded.
const data = await fs.promises.readFile('small.json', 'utf8'); // whole file
fs.createReadStream('huge.csv').pipe(parser); // chunked
The rule interviewers want: use readFile for small files you need fully in memory (config, small JSON); use createReadStream for large files or when piping (serving downloads, processing CSV/logs), since it's memory-efficient and supports backpressure. Both are non-blocking — the difference is all-at-once vs streamed.
Follow-up 1
Can you provide a code example of using createReadStream in Node.js?
Sure! Here's an example of using createReadStream to read a file in Node.js:
const fs = require('fs');
const readStream = fs.createReadStream('file.txt', { encoding: 'utf8' });
readStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
});
readStream.on('end', () => {
console.log('Finished reading the file.');
});
readStream.on('error', (error) => {
console.error('An error occurred:', error);
});
Follow-up 2
When should you use readFile over createReadStream?
You should use readFile when you need to read the entire contents of a small file into memory. Since readFile reads the entire file at once, it is more suitable for small files that can easily fit into memory. It is also simpler to use, as you don't need to handle the stream events.
However, if you are dealing with large files or want to process the file in chunks, you should use createReadStream. It allows you to read the file in smaller chunks, which is more memory-efficient and allows you to process the data as it becomes available.
Follow-up 3
What are the advantages of using createReadStream?
There are several advantages of using createReadStream in Node.js:
Memory efficiency:
createReadStreamallows you to read large files in smaller chunks, which reduces the memory usage compared to reading the entire file into memory at once usingreadFile.Performance: By reading the file in chunks,
createReadStreamallows you to start processing the data as soon as it becomes available, instead of waiting for the entire file to be read. This can significantly improve the performance, especially for large files.Streaming capabilities:
createReadStreamprovides various events and methods that allow you to handle the data stream, such asdata,end, anderrorevents. This gives you more control and flexibility in handling the file data.Scalability: Since
createReadStreamreads the file in chunks, it can handle large files without consuming excessive memory, making it more scalable for applications that deal with large amounts of data.
2. How does Node.js handle data?
Node handles data through a few core abstractions, and a strong answer names them:
- Buffers — fixed-length raw binary data (
Buffer), used for bytes from files, sockets, crypto, etc. - Streams — process data incrementally in chunks rather than all at once (readable, writable, duplex, transform). Essential for large data and I/O efficiency, with built-in backpressure.
JSON—JSON.parse/stringifyfor the most common structured-data format.- Encodings —
TextEncoder/TextDecoderand string encodings (utf8,base64) for converting between bytes and text.
import { pipeline } from 'node:stream/promises';
await pipeline(fs.createReadStream('in.csv'), transform, fs.createWriteStream('out.csv'));
The framing: Node is built for I/O-heavy data movement, so it favors streaming (constant memory, start processing early) over loading everything into memory. A current note: modern Node also implements the Web Streams API (ReadableStream/WritableStream) alongside its classic streams, plus global fetch, Blob, and structuredClone — so data handling increasingly aligns with web platform standards.
Follow-up 1
How does Node.js handle large amounts of data?
Node.js handles large amounts of data by using streams. Streams allow you to process data in chunks, which means that you don't have to load the entire data into memory at once. Instead, you can read or write data in smaller chunks, reducing memory usage and improving performance. This is especially important when dealing with large files or network communication.
Follow-up 2
How can you convert a buffer to a string in Node.js?
To convert a buffer to a string in Node.js, you can use the toString() method of the Buffer class. This method allows you to specify the encoding of the buffer, such as 'utf8' or 'ascii'. For example:
const buffer = Buffer.from('Hello, World!');
const str = buffer.toString('utf8');
console.log(str); // Output: Hello, World!
Follow-up 3
What is the role of buffers in data handling in Node.js?
Buffers in Node.js are used to handle binary data. They are instances of the Buffer class, which is a global object in Node.js. Buffers are used to store and manipulate binary data, such as images, audio, or network packets. They can be created from strings, arrays, or directly from raw binary data. Buffers provide methods for reading, writing, and manipulating binary data efficiently.
3. What are streams in Node.js and why are they important in data handling?
Streams are abstractions for processing data piece by piece (in chunks) as it's read or written, instead of buffering the whole payload in memory. They're central to Node because so much of what it does is move data (files, network, HTTP). The four types:
- Readable (
fs.createReadStream, request bodies), Writable (fs.createWriteStream, responses), Duplex (sockets), Transform (gzip, crypto, parsers).
Why they matter:
- Memory efficiency — process a 10 GB file with a few MB of RAM.
- Time efficiency — start working on early chunks before the rest arrives (lower latency).
- Composability — chain steps with
pipe/pipeline(read → transform → write). - Backpressure — built-in flow control prevents a fast producer from overwhelming a slow consumer.
import { pipeline } from 'node:stream/promises';
await pipeline(
fs.createReadStream('in.txt'),
zlib.createGzip(),
fs.createWriteStream('in.txt.gz')
);
The best-practice point: prefer pipeline() (from node:stream/promises) over manual .pipe(), because it propagates errors and cleans up all streams automatically — a raw .pipe() chain leaks resources on error. Modern Node also supports the standards-based Web Streams API.
Follow-up 1
What are the different types of streams in Node.js?
There are four types of streams in Node.js:
- Readable streams: These streams are used for reading data from a source.
- Writable streams: These streams are used for writing data to a destination.
- Duplex streams: These streams can be used for both reading and writing data.
- Transform streams: These streams are a type of duplex stream that can modify or transform the data as it is being read or written.
Follow-up 2
How do you handle errors in streams in Node.js?
To handle errors in streams in Node.js, you can listen for the 'error' event on the stream object. For example:
const fs = require('fs');
const readStream = fs.createReadStream('input.txt');
readStream.on('error', (error) => {
console.error('An error occurred:', error);
});
Follow-up 3
Can you provide a code example of using streams in Node.js?
Sure! Here's an example of using a readable stream to read data from a file and a writable stream to write the data to another file:
const fs = require('fs');
const readStream = fs.createReadStream('input.txt');
const writeStream = fs.createWriteStream('output.txt');
readStream.on('data', (chunk) => {
writeStream.write(chunk);
});
readStream.on('end', () => {
writeStream.end();
console.log('Data has been copied.');
});
4. How can you handle JSON data in Node.js?
JSON is a first-class citizen in Node (it's JavaScript), handled with the global JSON object:
JSON.parse(text)— string → JavaScript object.JSON.stringify(value[, replacer, space])— object → JSON string (with optional pretty-printing).
const obj = JSON.parse('{"id":1}');
const text = JSON.stringify(obj, null, 2);
Practical points interviewers reward:
- Always wrap
JSON.parseintry/catch— malformed input throwsSyntaxError. - Reading JSON files:
JSON.parse(await fs.readFile('data.json', 'utf8')); you can alsoimport data from './data.json' with { type: 'json' }(import attributes) orrequire('./data.json')in CommonJS. - In web frameworks, request bodies are parsed for you (
express.json()/ Fastify's built-in parser), and you send JSON withres.json(...). - For very large JSON,
JSON.parseloads everything into memory and can block the loop — use a streaming parser instead. stringifydropsundefined/functions and throws on circular references (use a custom replacer orstructuredClone-safe data).
Follow-up 1
How can you parse JSON data in Node.js?
To parse JSON data in Node.js, you can use the JSON.parse() method. This method takes a JSON string as input and returns a JavaScript object.
Follow-up 2
How can you stringify JSON data in Node.js?
To stringify JSON data in Node.js, you can use the JSON.stringify() method. This method takes a JavaScript object as input and returns a JSON string.
Follow-up 3
Can you provide a code example of handling JSON data in Node.js?
Sure! Here's an example of how you can handle JSON data in Node.js:
const jsonData = '{"name":"John","age":30,"city":"New York"}';
// Parsing JSON data
const parsedData = JSON.parse(jsonData);
console.log(parsedData);
// Stringifying JSON data
const stringifiedData = JSON.stringify(parsedData);
console.log(stringifiedData);
5. What is the role of the 'fs' module in data handling in Node.js?
The built-in fs ("file system") module is Node's API for interacting with files and directories: reading, writing, appending, deleting, renaming, watching, creating directories, and inspecting metadata/permissions (stat, chmod).
It comes in three flavors, and naming them signals competence:
fs/promises— promise-based; the modern default withasync/await.- Callback API — classic error-first callbacks (
fs.readFile(path, cb)). - Sync API —
fs.readFileSync, etc., which block the event loop — fine at startup, avoid in request handlers.
import { readFile, writeFile } from 'node:fs/promises';
const cfg = JSON.parse(await readFile('config.json', 'utf8'));
await writeFile('log.txt', 'done\n', { flag: 'a' });
Its role in data handling: load configuration, write logs/exports, manage uploaded files, and—crucially—provide createReadStream/createWriteStream for streaming large files with constant memory. Best practices to mention: prefer the promise API, avoid *Sync on hot paths, use the node: prefix, handle errors (missing files throw ENOENT), and use path/path.join for cross-platform paths. Note modern Node can also restrict fs access via the permission model.
Follow-up 1
What are some common methods provided by the 'fs' module?
Some common methods provided by the 'fs' module in Node.js are:
- fs.readFile(): Reads the contents of a file asynchronously.
- fs.writeFileSync(): Writes data to a file synchronously.
- fs.readdir(): Reads the contents of a directory asynchronously.
- fs.mkdir(): Creates a new directory asynchronously.
- fs.unlink(): Deletes a file asynchronously.
- fs.rename(): Renames a file or directory asynchronously.
- fs.stat(): Retrieves information about a file or directory asynchronously.
Follow-up 2
How can you read a file using the 'fs' module?
To read a file using the 'fs' module in Node.js, you can use the fs.readFile() method. This method reads the contents of a file asynchronously and returns the data in a callback function.
Here's an example of how to read a file using the 'fs' module:
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
Follow-up 3
Can you provide a code example of using the 'fs' module in Node.js?
Sure! Here's an example of how to use the 'fs' module in Node.js to create a new file and write data to it:
const fs = require('fs');
const data = 'Hello, world!';
fs.writeFile('file.txt', data, (err) => {
if (err) throw err;
console.log('File created and data written successfully!');
});
6. What is a Buffer in Node.js and when would you use one?
A Buffer is a fixed-length chunk of raw binary data stored outside the V8 heap. It exists because core JavaScript strings can't safely represent arbitrary bytes, and Node constantly deals with binary I/O — file contents, TCP sockets, streams, crypto, image/compression data.
const buf = Buffer.from('hello', 'utf8');
console.log(buf.length, buf.toString('hex')); // 5 68656c6c6f
const empty = Buffer.alloc(16); // zero-filled, safe
Points interviewers want: use Buffer.alloc(n) (zero-filled, safe) rather than the deprecated/unsafe new Buffer() or allocUnsafe (which can expose old memory) unless you immediately overwrite it; Buffers are returned by fs.readFile when you don't specify an encoding, and stream chunks are Buffers by default; and you convert with .toString(encoding) / Buffer.from(str, encoding) (utf8, base64, hex). Buffer is a subclass of Uint8Array, so it interoperates with the standard TypedArray/Web APIs — which is why modern Node code increasingly uses Uint8Array/TextEncoder alongside Buffers.
Live mock interview
Mock interview: Data Handling in Node.js
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.