Difficulty: Intermediate
Node.js interviews test your understanding of both the runtime's internals and practical application development. Interviewers want to know that you understand why Node.js behaves the way it does, not just how to use it. The event loop, non-blocking I/O, streams, and the module system are the most frequently asked topics because they define what makes Node.js unique.
The event loop is the heart of Node.js. It is what allows Node.js to handle thousands of concurrent connections with a single thread. When a request comes in, Node.js processes the synchronous code immediately and delegates I/O operations (file reads, database queries, network requests) to the operating system via libuv. When the I/O completes, a callback is placed in the appropriate event loop queue. The event loop continuously cycles through its phases: timers (setTimeout/setInterval), pending callbacks, poll (I/O), check (setImmediate), and close callbacks.
Streams are a fundamental pattern in Node.js for handling data that flows over time. Instead of reading an entire file into memory at once, a ReadableStream processes it chunk by chunk, keeping memory usage constant regardless of file size. There are four stream types: Readable (data source), Writable (data destination), Duplex (both readable and writable), and Transform (modifies data as it passes through). The pipe() method connects streams together. Streams are used everywhere in Node.js: HTTP request/response bodies, file operations, process stdin/stdout, and network sockets.
Middleware in Express is a powerful composition pattern. Each middleware function has access to the request object, the response object, and the next function. Middleware can execute code, modify req and res, end the request-response cycle, or pass control to the next middleware. This pattern enables clean separation of concerns: logging, authentication, parsing, validation, and error handling are each handled by their own middleware function, stacked in a pipeline.
RESTful API design is another core interview topic. REST (Representational State Transfer) uses HTTP methods to map to CRUD operations: GET for reading, POST for creating, PUT/PATCH for updating, DELETE for removing. URLs represent resources (/api/users, /api/users/42), not actions. RESTful APIs are stateless - each request contains all the information needed to process it, with no server-side session dependency. Status codes communicate the result: 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not Found), 500 (Server Error).
console.log('1. Synchronous - start');
setTimeout(() => {
console.log('2. setTimeout (macrotask)');
}, 0);
Promise.resolve().then(() => {
console.log('3. Promise.then (microtask)');
});
process.nextTick(() => {
console.log('4. process.nextTick (microtask, highest priority)');
});
setImmediate(() => {
console.log('5. setImmediate (check phase)');
});
console.log('6. Synchronous - end');
This reveals the event loop execution order. Synchronous code runs first (1, 6). Then microtasks: process.nextTick (4) has highest priority, followed by Promise.then (3). Then macrotasks: setTimeout (2) runs in the timer phase, setImmediate (5) in the check phase. This ordering is a very common interview question.
const { Readable, Transform, Writable } = require('stream');
// Create a readable stream (data source)
const readable = new Readable({
read() {
this.push('Hello ');
this.push('World ');
this.push('from ');
this.push('streams!');
this.push(null); // Signal end of data
}
});
// Create a transform stream (modifier)
const upperCase = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
// Create a writable stream (destination)
const chunks = [];
const writable = new Writable({
write(chunk, encoding, callback) {
chunks.push(chunk.toString());
callback();
}
});
writable.on('finish', () => {
console.log('Result:', chunks.join(''));
});
// Pipe: readable -> transform -> writable
readable.pipe(upperCase).pipe(writable);
console.log('Stream pipeline created');
console.log('Types: Readable -> Transform -> Writable');
Three streams are connected with pipe(). Data flows from the Readable source, through the Transform (which uppercases each chunk), to the Writable destination. Each chunk is processed independently, so even a terabyte file would use only a small buffer of memory.
// Q1: What is the difference between require() and import?
const q1 = {
require: 'CommonJS (CJS) - synchronous, dynamic, runs at runtime',
import: 'ES Modules (ESM) - async, static, analyzed at parse time',
key: 'require can be conditional (inside if), import cannot (must be top-level)'
};
// Q2: What is the difference between process.nextTick and setImmediate?
const q2 = {
nextTick: 'Runs before any I/O event in the current iteration',
setImmediate: 'Runs in the check phase of the next event loop iteration',
priority: 'nextTick > Promise.then > setTimeout > setImmediate'
};
// Q3: How does Node.js handle child processes?
const q3 = {
exec: 'Spawns shell, buffers output, good for small commands',
spawn: 'Spawns process, streams output, good for long-running processes',
fork: 'Special spawn for Node.js scripts, includes IPC channel',
worker_threads: 'Threads within the same process, share memory'
};
// Q4: What is middleware in Express?
const q4 = {
definition: 'Functions with (req, res, next) that process requests in a pipeline',
types: ['Application-level', 'Router-level', 'Error-handling', 'Built-in', 'Third-party'],
flow: 'Each calls next() to pass control or sends a response to end the cycle'
};
console.log('Q1 (require vs import):', q1.key);
console.log('Q2 (nextTick vs setImmediate):', q2.priority);
console.log('Q3 (child processes):', Object.keys(q3).join(', '));
console.log('Q4 (middleware types):', q4.types.length);
These are the most frequently asked Node.js interview questions. Understanding event loop phases, the difference between CJS and ESM modules, child process options, and Express middleware is essential. Practice explaining each concept clearly and concisely.
event loop, streams, middleware, REST API, error handling, scaling, libuv