Node.js interview questions: event loop, streams, modules and practice quiz

Reviewed by Mark Dickie · Last updated

4 questions on this page you can answer and see marked on the spot. Go to the first one

Node.js is a JavaScript runtime built on Chrome's V8 engine that runs server code on one thread with an event loop. Interviewers mostly probe how that loop handles I/O, so expect questions on the order of timers, process.nextTick, promise callbacks and setImmediate. You should also explain why one synchronous CPU-heavy function stalls every open connection, and when worker_threads or cluster fixes it. Module loading (CommonJS versus ES modules) and streams come up often too.

What does a Node.js interview test?

TopicWhat you should explainConcrete check
Event loop phasesTimers, pending callbacks, poll, check, close, and where I/O callbacks runPredict whether setTimeout or setImmediate fires first inside an fs.readFile callback
Microtasks and nextTickprocess.nextTick drains before promise jobs in the same tickOrder the output of nextTick, Promise.then and queueMicrotask called in one script
libuv thread poolfs, dns.lookup and crypto.pbkdf2 run on a pool of 4 threads by defaultExplain why a fifth pbkdf2 call waits, and what UV_THREADPOOL_SIZE changes
StreamsBackpressure through highWaterMark and the boolean returned by write()Why pipe() alone does not forward errors, and what stream.pipeline() adds
Module systemrequire cache, module.exports versus exports, the exports field in package.jsonWhy top-level await fails in a CommonJS file
Error handlingUnhandled promise rejections terminate the process by defaultAttach an 'unhandledRejection' listener and say why it is a last resort
Scalingcluster forks processes that share a port; worker_threads shares memory via SharedArrayBufferChoose one for a CPU-bound image resize and justify the choice

Which hands-on exercises prepare you best?

  1. Block the loop with a synchronous loop inside one route, then move that work into a worker_threads Worker and compare response times under parallel requests.
  2. Write a file copy with stream.pipeline and an AbortController, then abort midway and confirm both file handles close.
  3. Convert a small CommonJS module to ESM and list which globals such as __dirname and require no longer exist.
  4. Start an HTTP server with cluster, kill one worker, and watch how the primary process replaces it.

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 tracked 1,070 job postings asking for Node.js in October 2026.
  • Roles asking for Node.js advertise a median base salary of £80,000, across 231 job postings as of October 2026.
  • Tarmac last reviewed these Node.js interview questions on 2 November 2026.

At a glance

Questions10 shown · 101 in the bank
Difficulty1–5 of 5
FormatsMultiple choice, Coding exercise, True / false, Fill in the blank, Multiple answer, Find the bug, Flashcard, Ordering, Code output, Short answer
Interactive1 run your code against tests, in the app

What you'll review

  1. commonjs
  2. middleware
  3. file system
  4. streams
  5. error first callbacks
  6. clustering
  7. node event loop
  8. async context

Practice questions

Try one before you open the answer. Pick an option and press Check; it's marked on the spot.

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.

Why:

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.

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.

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.

Why:

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.

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").

Why:

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.

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().

Why:

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.

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.

Why:

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) ...; }.

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).

Why:

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.

This runs top to bottom:#

Put these in order

Show answer

The logs appear in this order:

  1. A (synchronous)
  2. D (process.nextTick)
  3. C (promise microtask)
  4. 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.

Why:

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.

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
Why:

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.

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.

Why:

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

Job market

See nodejs salaries and hiring demand from live job postings.

The other 91 questions

This page shows 10 and marks what you pick. That's as far as a page can go. A free account opens the other 91 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.

Start with this topic

Free · the whole bank · 100 answers per 30 days, each marked with written feedback

Interview booked? Practise the job ad instead

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.