Node.js Interview Questions — Practice Real Interview Problems
Reviewed by Mark Dickie · Last updated
Node.js is a JavaScript runtime built on Chrome's V8 engine that lets you run JavaScript outside the browser, most often on servers. For interviews, the event loop is the spine of almost every question: you need to know how Node processes asynchronous work across its phases, when microtasks run versus macrotasks, and why blocking the main thread is the cardinal sin. Beyond that, expect questions on streams, the CommonJS/ESM module split, error-first callbacks and Promises, memory leaks, and how to profile a slow process.
What does a Node.js interview typically test?
| Topic | What gets asked |
|---|---|
| Event loop | Phase order, microtask vs macrotask scheduling, process.nextTick vs setImmediate |
| Streams | Piping, backpressure, transform streams, error propagation |
| Modules | CommonJS require vs ESM import, circular dependencies |
| Async patterns | Promises, async/await, error-first callbacks, Promise.all vs allSettled |
| Performance & memory | Memory leaks, --max-old-space-size, CPU profiling, clustering |
| Built-in modules | fs, http, path, child_process, worker_threads |
How should I prepare for a Node.js interview?
- Write out the event loop phases from memory and explain what runs in each one.
- Build a small HTTP server that serves files through streams and add backpressure handling.
- Convert a callback-based function into a Promise, then into
async/await. - Create a memory leak on purpose, then track it down with
--inspectand a heap snapshot. - Set up a cluster or use
worker_threadsto run CPU-bound work without blocking the event loop.
Senior-level interviews also dig into runtime internals: V8's garbage collector, libuv's thread pool (default size 4), and how worker_threads differ from child processes. Knowing where the built-in http module ends and where a framework like Express or Fastify picks up shows the kind of practical judgment interviewers look for. If you can explain why Node is single-threaded yet still handles thousands of concurrent connections, you have the mental model most candidates are missing.
Key facts
- Tarmac has 101 Node.js interview questions on this topic, 10 of them on this page, at difficulty 1–5 of 5.
- Tarmac last reviewed these Node.js interview questions on 18 August 2026.
At a glance
| Questions | 10 shown · 101 in the bank |
|---|---|
| Difficulty | 1–5 of 5 |
| Formats | Coding exercise, Multiple choice, True / false, Fill in the blank, Multiple answer, Find the bug, Flashcard, Ordering, Code output, Short answer |
| Interactive | 1 run your code against tests, in the app |
What you'll review
- middleware
- commonjs
- file system
- streams
- error first callbacks
- clustering
- node event loop
- async context
Practice questions
Node.js/node-http/middleware
In Node.js HTTP servers, middleware functions typically receive (req, res, next) and modify the request or response before passing control along. Implement a simple logging middleware function loggingMiddleware(req, res) that:#
Starter code
function loggingMiddleware(req, res) {
// TODO: Set res.headers['X-Request-ID'] to req.id or 'unknown'
// TODO: Set res.statusCode to 200
// TODO: Return res
return res;
}
Your solution must pass
- sets header from req.id
This one is written and run, not read. Solve it in the app and your code is executed against these tests and the hidden ones.
Node.js/node-modules/commonjs
In a CommonJS module (a .js file loaded with require), which of these is a real, module-scoped variable Node injects automatically?#
Options
Show answer
__dirname is the real module-scoped variable Node injects automatically. Node wraps every CommonJS module in a function that receives exports, require, module, __filename, and __dirname as parameters, so it is available without any import. import.meta only exists in ES modules, and window is a browser global.
Node wraps every CommonJS module in a function that receives exports, require, module, __filename, and __dirname as parameters, so __dirname is available without importing anything. import.meta only exists in ES modules; window is a browser global.
Node.js/node-modules/commonjs
In CommonJS, calling require("./config") twice in the same process returns the same cached module object the second time.#
Options
Show answer
True. require caches a module's exports in require.cache keyed by the resolved filename, and the module's top-level code runs only on the first call. Every later require of the same path returns that same cached object, making the module effectively a singleton per process.
require caches a module's exports in require.cache keyed by its resolved filename. The module's top-level code runs only on the first require; subsequent calls return the same exported object, so the module is effectively a singleton per process.
Node.js/fs-io/file-system
To read a file with async/await using the promise-based API, you import from fs/_____ and call await _____(path, "utf8").#
Show answer
To read a file with async/await using the promise-based API, you import from fs/**promises** and call await **readFile**(path, "utf8").
The promise-based file API lives at fs/promises (also reachable as fs.promises). Its readFile(path, encoding) returns a Promise of the contents, so it can be awaited directly — unlike the callback-style fs.readFile.
Node.js/runtime/streams
Which of the following are among the four fundamental stream types in Node's stream module?#
Options
Pick every one that applies.
Show answer
The four fundamental stream types are Readable, Writable, Duplex, and Transform — not Mutable, which does not exist. A Duplex is both readable and writable, and a Transform is a Duplex whose output is computed from its input, such as zlib.createGzip().
The four base stream types are Readable, Writable, Duplex (both readable and writable), and Transform (a Duplex whose output is computed from its input, e.g. zlib.createGzip()). There is no "Mutable" stream type.
Node.js/async-patterns/error-first-callbacks
This reads a file but will crash on the happy path instead of handling failures. Which line is the bug?#
const fs = require('fs');
fs.readFile('./data.json', 'utf8', (data) => {
console.log(JSON.parse(data));
});Show answer
The bug is on line 2.
Node's error-first callbacks receive (err, data) — the first argument is the error. The callback here binds the first argument to data, so data is actually the error (usually null on success), and the real file contents are dropped. It must be (err, data) => { if (err) ...; }.
Node.js/scaling/clustering
When would you reach for the cluster module versus worker_threads?#
Show answer
Use cluster to fork multiple processes of the same server to use all CPU cores for I/O-bound, request-serving workloads (each worker has its own memory and event loop, sharing a listening port). Use worker_threads for CPU-bound work you want to run in parallel within one process (shared-nothing by default, but able to share memory via SharedArrayBuffer and transfer buffers cheaply).
cluster scales an I/O server horizontally across cores using separate processes; worker_threads offloads CPU-heavy computation to threads in the same process. They solve different problems — concurrency of requests vs parallelism of computation.
Node.js/runtime/node-event-loop
This runs top to bottom:#
Put these in order
Show answer
The logs appear in this order:
A(synchronous)D(process.nextTick)C(promise microtask)B(setTimeout)
Synchronous code runs first, then the process.nextTick queue drains before the promise microtask queue, and the setTimeout callback is a timers-phase macrotask that runs last.
Synchronous code runs first (A). Before the event loop moves on, the process.nextTick queue drains (D), then the promise microtask queue (C). The setTimeout callback (B) is a timers-phase macrotask, so it runs last.
Node.js/runtime/node-event-loop
In what order does Node log these four lines?#
console.log('sync');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));Show answer
sync
nextTick
promise
timeout
Synchronous code runs first (sync). Before the event loop advances to any phase, Node drains the process.nextTick queue, then the promise microtask queue — so nextTick precedes promise. The setTimeout callback is a timers-phase macrotask and runs last.
Node.js/async-patterns/async-context
What problem does AsyncLocalStorage solve, and how does it work at a high level?#
Show answer
AsyncLocalStorage (from node:async_hooks) provides per-request context that survives across asynchronous boundaries — callbacks, promises, and awaits — without threading a value through every function argument. You call store.run(context, callback) to establish a context, and any code executing within that asynchronous call chain can retrieve it with store.getStore(). It is commonly used to carry a request id or trace id through a whole request lifecycle for logging.
AsyncLocalStorage ties a store to an asynchronous execution context so values set with run() are readable via getStore() anywhere downstream in that chain, even after await. It is the idiomatic way to propagate request-scoped data (request/trace ids, user) without passing it explicitly everywhere.
Sources
The official documentation these questions are checked against:
Related interview questions
The other 91 questions
This page shows 10. A free account opens the rest and marks your answers, which a page of answers can't do. Miss one and it returns a few days later, then a week after that, until you stop missing it.
Free · the whole bank · 100 graded answers per 30 days · written feedback and job-ad quizzes on the paid plan