Node.js interview questions and answers, junior to senior
These are the Node.js questions backend and full-stack interviews actually ask, with short answers you can give out loud and small code examples where they help. They are grouped by level: junior questions check the event loop and modules, mid-level ones check streams, errors and what blocks a server, senior ones check scaling, diagnostics and security. Every answer was checked against the Node.js API documentation and the Node.js Learn guides in October 2026.
How Node.js questions show up in interviews
In a backend loop, Node.js questions rarely come as a quiz. They come as "this endpoint gets slow under load, why?" or as a follow-up to code you wrote in a live round: why await inside a loop, what happens if this promise rejects. The answers below are short on purpose: name the mechanism, give one example, say the trade-off. For the round formats themselves, see the live coding guide and the technical phone screen guide.
Junior Node.js interview questions
1. Is Node.js single-threaded?
Your JavaScript runs on one main thread with one event loop. Node.js itself is not single-threaded: libuv keeps a thread pool for work that has no non-blocking OS API, and worker_threads can run JavaScript in parallel. The practical consequence is that one slow synchronous function delays every request the process is handling.
2. What are the phases of the event loop?
Per the Node.js guide, each loop iteration goes through: timers (setTimeout and setInterval callbacks), pending callbacks (some deferred I/O callbacks), idle, prepare (internal), poll (retrieve new I/O events and run their callbacks; Node may block here), check (setImmediate) and close callbacks (The Node.js Event Loop). A detail interviewers like: since libuv 1.45.0 (Node.js 20), timers run after the poll phase in each iteration.
3. In what order do process.nextTick, promises, setImmediate and setTimeout run?
process.nextTick callbacks run after the current operation finishes, before the event loop continues; promise callbacks (microtasks) run right after them. setImmediate runs in the check phase. Between setTimeout(fn, 0) and setImmediate the order is not guaranteed in the main module, but inside an I/O callback the immediate always runs first. The guide recommends setImmediate in most cases, and warns that recursive nextTick calls can starve I/O.
const fs = require('node:fs');
fs.readFile(__filename, () => {
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
process.nextTick(() => console.log('nextTick'));
});
// nextTick, immediate, timeout4. What is the difference between CommonJS and ES modules in Node.js?
CommonJS uses require and module.exports and loads synchronously; ES modules use import and export, are loaded asynchronously and allow top-level await. Node decides by extension and the nearest package.json: .mjs is ESM, .cjs is CommonJS, and .js follows the "type" field (Modules: CommonJS). Current releases can also require() a synchronous ES module; it stopped needing a flag in Node.js 22.12 and 20.19, and a module with top-level await throws ERR_REQUIRE_ASYNC_MODULE and must be loaded with import().
5. Callbacks, promises or async/await?
Older core APIs use error-first callbacks, (err, result) => {}. Most now have promise versions, such as node:fs/promises, and util.promisify converts the rest. async/await is promises with linear syntax. A common follow-up: awaiting inside a loop runs the calls one after another; Promise.all runs them concurrently, and Promise.allSettled when one failure should not cancel the rest.
6. What happens when an EventEmitter emits error with no listener?
The error is thrown, a stack trace is printed and the process exits. The docs recommend always adding an 'error' listener, and advise against async functions as error handlers (Events: error events).
const { EventEmitter } = require('node:events');
const bus = new EventEmitter();
bus.on('error', (err) => console.error('handled:', err.message));
bus.emit('error', new Error('boom')); // logged, process keeps running7. What is a Buffer?
A fixed-length sequence of bytes, a subclass of Uint8Array, used for binary data: files, sockets, hashes. Converting to a string needs an encoding, and a multi-byte UTF-8 character split across two chunks will decode wrongly unless you decode the stream as a whole or use setEncoding (Buffer).
8. What is the difference between dependencies and devDependencies, and why commit the lockfile?
dependencies are needed at runtime; devDependencies only for building and testing, and are skipped in production installs. The lockfile pins the exact resolved versions so every install gets the same tree. The Node.js security guide adds the supply-chain angle: pin dependencies to specific immutable versions and run automatic vulnerability checks.
Mid-level Node.js interview questions
9. What kinds of streams are there, and what is backpressure?
Readable, Writable, Duplex and Transform. Backpressure is data building up when the consumer is slower than the producer. writable.write() returns false once the internal buffer reaches highWaterMark; you should stop writing and wait for the 'drain' event. The docs stress that highWaterMark is a threshold, not a hard memory limit (Backpressuring in Streams).
10. Why use stream.pipeline() instead of .pipe()?
With .pipe(), an error in the source does not close the destination; you have to destroy each stream yourself or leak them. pipeline() forwards errors, cleans up every stream in the chain and tells you when it is done; the promise version also takes an AbortSignal (Stream).
const { pipeline } = require('node:stream/promises');
const fs = require('node:fs');
const zlib = require('node:zlib');
await pipeline(
fs.createReadStream('access.log'),
zlib.createGzip(),
fs.createWriteStream('access.log.gz'),
);11. What blocks the event loop?
Anything synchronous and long: fs.readFileSync in a request handler, JSON.parse or JSON.stringify on very large payloads, synchronous crypto such as pbkdf2Sync, heavy loops, and regular expressions with catastrophic backtracking on user input. The Node.js guide Don't Block the Event Loop covers each case. The fixes are to stream or chunk the work, use the async API, or move CPU work to a worker thread.
12. What runs on the libuv thread pool?
Per the CLI docs: all fs APIs except the file watchers and explicitly synchronous ones, async crypto such as pbkdf2, scrypt, randomBytes and generateKeyPair, dns.lookup(), and all non-synchronous zlib APIs. The default size is 4, changed with UV_THREADPOOL_SIZE, which has to be set in the environment before Node starts (CLI: UV_THREADPOOL_SIZE). Network I/O does not use the pool.
13. What happens to an unhandled promise rejection?
Since Node.js 15 the default mode is throw: Node emits 'unhandledRejection', and if no handler is registered the rejection is raised as an uncaught exception, which crashes the process (CLI: --unhandled-rejections). A good answer adds that a global handler is for logging and a clean exit, not for carrying on as if nothing happened.
14. How do you handle errors in async code?
try/catch around await, a .catch() on every promise you do not await, and an error listener on every emitter and stream. Distinguish expected failures, such as a missing record or a timeout, from bugs: handle the first close to where they happen, let the second crash the process and restart it. For cancellation and timeouts, pass an AbortSignal; many core APIs accept one.
const res = await fetch(url, { signal: AbortSignal.timeout(3000) });15. How do you shut a Node.js server down gracefully?
Handle SIGTERM (what orchestrators send), stop accepting new connections with server.close(), let in-flight requests finish, close database pools, then exit. Add a hard timeout so a stuck connection cannot keep the process alive forever.
process.on('SIGTERM', () => {
server.close(() => db.end().then(() => process.exit(0)));
setTimeout(() => process.exit(1), 10_000).unref();
});16. What is AsyncLocalStorage used for?
Carrying per-request context, such as a request ID or the current user, through async calls without passing it as an argument to every function. It is the standard way to get request IDs into logs (Asynchronous context tracking).
Senior Node.js interview questions
17. worker_threads, cluster or child_process?
Workers run JavaScript in parallel threads inside one process and can share memory by transferring ArrayBuffer or sharing SharedArrayBuffer. The docs are explicit that they help with CPU-intensive JavaScript and do not help much with I/O (Worker threads). cluster forks processes that share a server port; child_process runs any program. The cluster docs themselves say to use worker threads when process isolation is not needed (Cluster).
18. How do you use all CPU cores for an HTTP service?
Several processes: the cluster module, which by default distributes connections round-robin on every platform except Windows, or, more often today, several containers or instances behind a load balancer. Either way the processes do not share memory, so sessions, caches and rate limits must live in an external store. The cluster docs warn against relying on in-memory data for sessions and login.
19. How would you find a memory leak?
Confirm the leak first: memory that keeps rising across garbage collections under steady load. Then take heap snapshots a few minutes apart, with --inspect and Chrome DevTools or v8.writeHeapSnapshot(), and compare what is growing. The usual causes are unbounded caches and maps, listeners added per request and never removed (a MaxListenersExceededWarning is the hint), timers that are never cleared, and closures holding large objects (Diagnostics: Memory).
20. Which security threats does the Node.js guide list for servers?
Among others: denial of service against the HTTP server (put it behind a reverse proxy and set timeouts), DNS rebinding through an exposed inspector (never run the inspector in production), HTTP request smuggling (do not use insecureHTTPParser), timing attacks on secret comparison (use crypto.timingSafeEqual), malicious third-party modules and supply-chain attacks (pin versions, audit), and prototype pollution (validate untrusted JSON against a schema) (Security Best Practices).
21. What is the Node.js Permission Model?
Started with --permission, Node restricts file system access, network access, spawning processes, worker threads, native addons, WASI and the inspector unless you grant them with flags such as --allow-fs-read. It has been stable since Node.js 22.13 and 23.5. The docs call it a "seat belt" for trusted code, not a sandbox: it does not provide security guarantees against malicious code (Permissions).
node --permission --allow-fs-read=./config --allow-fs-write=./logs server.js22. Can Node.js run TypeScript directly?
Yes, by type stripping: Node replaces type annotations with whitespace and runs the result. It is on by default since Node.js 23.6 and 22.18 and is now stable. It does no type checking and ignores tsconfig.json; syntax with runtime meaning, such as enums, namespaces with code and parameter properties, is not supported, and type-only imports need the type keyword (Modules: TypeScript). Keep tsc --noEmit in CI for the actual checking.
23. What does modern Node.js ship that used to need packages?
A global fetch, a test runner in node:test, --watch mode, --env-file for loading environment files, AbortController, Web Streams and the TypeScript type stripping above. A senior answer is not a list, though: it is knowing when a built-in is enough and when a dependency is worth its supply-chain cost.
24. How would you design a rate limiter for a Node.js API running on several instances?
Not in process memory, because each instance would count separately. Keep counters in a shared store with atomic increments and expiry, use a fixed or sliding window or a token bucket, key by API key or user rather than only by IP, and return 429 with Retry-After. This is a system design question as much as a Node one; the system design interview framework shows how to structure the answer.
How to practise these answers
- Run the examples. The event loop ordering question is easy to answer wrongly from memory and easy to answer correctly after running six lines.
- Have one production story per topic. A memory leak you found, a slow endpoint you fixed, an outage caused by an unhandled rejection. Interviewers trust a real story more than a definition, and the behavioral questions guide covers how to tell it.
- Practise the coding round separately. Most Node.js loops also include an algorithm or API-building exercise; the technical interview preparation plan and the take-home assignment guide cover those.
Where Interview Copilot fits
We make Interview Copilot, a desktop app that listens to the call and puts a suggested answer on your screen, so this paragraph is about our own product. In a knowledge round it can bring up the mechanism behind a question, say the event loop phases, while you are answering. It does not replace understanding the material, and it belongs only in interviews where your own tools are allowed: if you are not sure, ask the recruiter before the round starts.
Sources
- Node.js Learn — The Node.js Event Loop
- Node.js Learn — Don't Block the Event Loop
- Node.js Learn — Backpressuring in Streams
- Node.js Learn — Security Best Practices
- Node.js Learn — Diagnostics: Memory
- Node.js API — Modules: CommonJS (loading ES modules with require)
- Node.js API — Modules: ECMAScript modules
- Node.js API — Events
- Node.js API — Stream
- Node.js API — Worker threads
- Node.js API — Cluster
- Node.js API — Command-line options (--unhandled-rejections, UV_THREADPOOL_SIZE)
- Node.js API — Permissions
- Node.js API — Modules: TypeScript
- Node.js API — Asynchronous context tracking
Documentation was read on 27 October 2026. Version notes refer to the history tables in the Node.js docs; check the release line your team runs.
FAQ
What are the most common Node.js interview questions?
How the event loop works and in what order nextTick, promises, setImmediate and setTimeout run; CommonJS versus ES modules; streams and backpressure; error handling and unhandled rejections; what blocks the event loop; and worker threads versus cluster. Senior interviews add memory leaks, scaling across cores and security.
Is Node.js single-threaded?
Your JavaScript runs on a single main thread with one event loop, but Node.js is not single-threaded overall: libuv has a thread pool, four threads by default, for file system, DNS lookup, some crypto and zlib work, and worker_threads can run JavaScript in parallel.
What is the difference between process.nextTick and setImmediate?
process.nextTick runs its callback after the current operation, before the event loop moves on, so recursive calls can starve I/O. setImmediate runs in the check phase of the next loop iteration. The Node.js guide recommends setImmediate in most cases because it is easier to reason about.
When should I use worker threads in Node.js?
For CPU-heavy JavaScript such as image processing, parsing or hashing large inputs. The Node.js docs say workers do not help much with I/O-heavy work, because the built-in asynchronous I/O is already more efficient than threads would be.
Can require() load an ES module?
Yes, in current Node.js releases, as long as the module has no top-level await. The feature stopped needing a flag in Node.js 22.12 and 20.19. If the module or anything it imports uses top-level await, require throws ERR_REQUIRE_ASYNC_MODULE and you need import() instead.
How should I prepare for a senior Node.js interview?
Be ready to explain the event loop precisely, debug a slow or leaking service from symptoms, choose between worker threads, cluster and separate instances, design shared state such as rate limiting across instances, and name the main security risks from the Node.js security guide with their fixes.