Top 30 Advanced Node.js & Express Interview Questions and Answers
30 advanced multiple-choice Node.js & Express interview questions, the deep end: internals, failure modes, and the design calls a senior engineer is expected to defend. They come from 30 bites in the Node.js & Express library, the hardest slice of the 134 Node.js & Express interview questions in the library. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.
Node.js, Express, Fastify, NestJS, Bun, Deno
30 questions. Pick an answer, or open “Show the answer” to read it.
Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.
Question 1 of 30
When module B requires module A in the middle of A's own loading, what does B receive?
Show the answer
Answer: c · A's exports object as populated so far, possibly incomplete
CommonJS caches the exports object at load start and returns it as-is, so B gets whatever A has assigned up to that point. It is not re-executed, does not throw, and the reference is not retroactively backfilled.
Read the full bite: Circular dependencies in CommonJS modules
Question 2 of 30
Why can two installed major versions of the same library cause instanceof checks to fail across packages?
Show the answer
Answer: b · Each copy is a distinct module instance with its own classes, so cross-copy instanceof returns false
Two physical copies are separate module instances with separate class identities, so an object from one copy is not an instance of the other copy's class. npm does not strip prototypes.
Read the full bite: Diamond dependencies and nested node_modules
Question 3 of 30
What is a distinctive advantage of monorepo workspaces over consuming shared code as published private packages?
Show the answer
Answer: d · A breaking change and all consumer updates can land in one atomic commit without a publish step
Workspaces link internal packages locally, so changes to shared code and its consumers ship in a single atomic commit. Published packages instead require a publish-and-bump cycle and risk version drift.
Read the full bite: Monorepo workspaces vs private npm packages
Question 4 of 30
Why does a worker-pool design usually finish faster than processing fixed chunks of ten sequentially?
Show the answer
Answer: a · It keeps ten requests always in flight instead of waiting for each chunk's slowest item
Fixed chunks must wait for the slowest request in each batch before starting the next, leaving slots idle. A worker pool immediately refills a freed slot, maintaining full concurrency throughout.
Read the full bite: Bounded concurrency for many async requests
Question 5 of 30
When is Promise.allSettled the better choice over Promise.all?
Show the answer
Answer: c · When each operation is independent and you need every outcome, including failures, reported
allSettled waits for every input and reports each outcome, ideal when partial success is acceptable and you must see all failures. all aborts on the first rejection, hiding other results.
Question 6 of 30
Why is for await...of preferable to Promise.all for processing a multi-gigabyte file line by line?
Show the answer
Answer: c · It consumes lines lazily one at a time, keeping memory bounded with backpressure
for await...of awaits each item before requesting the next, so only one line is held at a time and memory stays flat. Promise.all would require buffering every line in memory at once.
Read the full bite: Async iterators and for await...of for streaming
Question 7 of 30
In a cluster setup, what is the primary (master) process responsible for?
Show the answer
Answer: a · Forking and supervising worker processes while workers serve traffic
The primary forks workers and restarts them on exit; the workers handle requests across cores. It does not serve traffic itself, share a heap, or run the heavy compute.
Read the full bite: Scaling across cores with cluster and os
Question 8 of 30
What advantage does stream.pipeline have over the .pipe() method when streaming a file to an HTTP response?
Show the answer
Answer: a · pipeline propagates errors and destroys all streams on failure, preventing leaks
pipeline adds unified error handling and resource cleanup that pipe lacks, avoiding leaked descriptors. Both honor backpressure; pipeline does not skip buffering, drop backpressure, or encrypt data.
Question 9 of 30
Why does enabling keepAlive on an http.Agent improve performance for repeated requests to the same host?
Show the answer
Answer: c · It reuses pooled sockets, skipping the TCP and TLS handshakes on later requests
keepAlive keeps sockets in the pool for reuse, avoiding repeated handshakes that add round trips. It does not compress, parallelize across cores, or cache responses.
Question 10 of 30
When mounting a router with app.use('/users', usersRouter), how should routes inside the router file be defined?
Show the answer
Answer: d · Relative to the mount point, like router.get('/:id'), which resolves to /users/:id
The mount prefix is prepended automatically, so routes are defined relative to it; router.get('/:id') becomes /users/:id. Repeating /users yields a doubled /users/users path.
Question 11 of 30
Why must auth middleware return after sending res.status(401) when the key is invalid?
Show the answer
Answer: b · To stop execution so it does not also call next and trigger a double response
Without returning, the function would continue and could call next, sending a second response and causing a headers-already-sent error. The return simply halts the handler; it does not free memory or reset status.
Question 12 of 30
What distinguishes an Express error-handling middleware from a regular one?
Show the answer
Answer: a · It has four parameters (err, req, res, next), and Express detects this signature
Express identifies error handlers by their four-argument arity and routes errors to them. The name is irrelevant, there is no app.error method, and it is still registered with app.use.
Question 13 of 30
Your JWT middleware sends a 401 for bad tokens but crashes with 'Cannot set headers after they are sent'. What is the bug?
Show the answer
Answer: b · It calls next() after sending the 401 response
After responding you must return without calling next(), or the chain continues and a later handler tries to send again. verify (not decode) is exactly what you want for security.
Question 14 of 30
You want an XML parser to run only for application/xml requests, with the condition kept out of the parser's own code. Which is the cleanest approach?
Show the answer
Answer: d · Use express.text({ type: 'application/xml' }) or a wrapper that checks req.is() then delegates
The type option and a req.is() wrapper keep the matching logic declarative and outside the parser, exactly what the question asks; embedding the check inside the parser is the disallowed approach.
Read the full bite: Conditionally apply middleware by request property
Question 15 of 30
In an Express 4 API with a central error middleware, async route errors still hang the request while sync throws work fine. What is missing?
Show the answer
Answer: b · An asyncHandler wrapper that catches promise rejections and calls next
Express 4 auto-catches synchronous throws but not promise rejections, so async handlers need a wrapper that forwards rejections to next. Moving the error handler before routes would actually break it.
Read the full bite: Centralized error handling in an Express API
Question 16 of 30
A team picks header-based API versioning over URL-path versioning. Which downside are they accepting?
Show the answer
Answer: b · Versions are hidden, harder to test in a browser, and complicate caching (Vary)
Header versioning keeps URLs clean but hides the version, making it less discoverable, harder to curl, and requiring caches to Vary on the header. Both strategies still let versions coexist.
Read the full bite: API versioning: URL vs header strategies
Question 17 of 30
You fetch 50 blogs and Sequelize logs 51 SQL queries. What single change most directly reduces this to one query?
Show the answer
Answer: a · Pass include for the Author model in the findAll call
Eager loading via include builds one JOIN query, eliminating the per-row author lookups. An index speeds each query but leaves the count at 51.
Read the full bite: Solving the N+1 query problem in Sequelize
Question 18 of 30
In a managed Sequelize transaction you create an Order with the transaction but decrement Product stock without passing it. What goes wrong?
Show the answer
Answer: d · The stock decrement commits independently and is not rolled back
A query that omits the transaction option runs outside it and commits on its own, so a later rollback cannot undo the stock change. Only queries passed the transaction participate in atomicity.
Read the full bite: Atomic order creation with Sequelize transactions
Question 19 of 30
You group sales by productId to compute totalSales, then want only products above 1000. Where must that $match stage go?
Show the answer
Answer: d · After $group, because totalSales does not exist until grouping
totalSales is a field created by $group, so a $match referencing it must come afterward. Placing $match first could only filter raw input fields, not the aggregated total.
Read the full bite: MongoDB aggregation pipeline for total sales
Question 20 of 30
Where should the role used by an RBAC middleware come from to remain secure?
Show the answer
Answer: c · The verified token payload or database lookup, set by auth middleware
The role must derive from a trusted source the client cannot forge, namely the verified token or a server-side lookup populated during authentication. Client-controlled headers, body, or query params can be spoofed to escalate privileges.
Read the full bite: Role-based access control middleware in Express
Question 21 of 30
You add a Redis denylist checked on every request to revoke JWTs instantly. What is the main trade-off you accept?
Show the answer
Answer: d · You reintroduce a per-request stateful lookup, reducing statelessness
A denylist gives immediate revocation but requires checking external state on each request, partly undoing the stateless advantage of JWTs. It has nothing to do with the signing algorithm or payload encryption.
Question 22 of 30
You move a JWT from localStorage into an httpOnly cookie. Which new defense becomes necessary that was not needed before?
Show the answer
Answer: a · CSRF protection such as SameSite or anti-CSRF tokens
httpOnly cookies are sent automatically by the browser, exposing the app to CSRF, so SameSite or anti-CSRF tokens are required. With localStorage the token was attached manually and not auto-sent, so CSRF was not a concern there.
Read the full bite: JWT storage: localStorage versus httpOnly cookies
Question 23 of 30
After catching an uncaughtException, why is the recommended action to log and exit rather than keep the server running?
Show the answer
Answer: c · Reaching this handler means an error escaped all handling, so process state is untrustworthy
An uncaughtException means an error bypassed every local handler, so the process may be in a corrupted state and should restart cleanly under a supervisor. Node does not auto-exit (in older versions) or auto-restart, which is exactly why you must exit deliberately.
Read the full bite: Handling uncaughtException and unhandledRejection
Question 24 of 30
Why can wrapping each integration test in a transaction that is rolled back afterward sometimes fail to isolate state?
Show the answer
Answer: c · If the code under test commits or uses a second connection, the rollback no longer covers all changes
Rollback only undoes work inside that transaction and connection; code that commits or opens another connection escapes it. Rollback is generally faster than truncation, so speed is not the issue.
Read the full bite: Managing clean test state across API integration tests
Question 25 of 30
What is the main drawback of testing a third-party integration by mocking your own client wrapper module rather than intercepting at the HTTP layer?
Show the answer
Answer: b · It bypasses request construction and the HTTP layer, leaving header and serialization bugs untested
Mocking your own wrapper skips the real request-building and transport code, so serialization or header bugs go uncaught. It is actually faster than real calls and needs no sandbox account.
Read the full bite: Testing code that calls a third-party API
Question 26 of 30
When testing an API call that writes to a database and then publishes to a message queue, why is a fixed setTimeout a poor way to wait for completion?
Show the answer
Answer: d · It is flaky under load yet slow when over-padded; polling-until-asserted is more reliable
A fixed delay races against variable latency: too short and it flakes, too long and it wastes time. Retrying an assertion until it passes within a timeout adapts to actual completion.
Read the full bite: Testing an async workflow that spans DB and message queue
Question 27 of 30
How can a strict CSP permit the SPA's own inline bootstrap script while still blocking attacker-injected inline scripts, without using unsafe-inline?
Show the answer
Answer: d · By stamping a fresh per-request nonce on trusted inline tags and listing it in script-src
A per-request nonce on trusted tags, matched in script-src, lets your code run while injected scripts lack the unpredictable nonce and are blocked. unsafe-eval concerns eval, not inline tags, and the other options weaken or void the policy.
Read the full bite: Deploying a strict CSP for an Express SPA
Question 28 of 30
Why is prototype pollution dangerous beyond the single object an attacker targets?
Show the answer
Answer: b · Writing to Object.prototype makes the injected property visible on every object that does not override it
Because objects inherit from the shared Object.prototype, a property set there leaks into all objects lacking their own value, enabling app-wide effects. It is not scoped to one request or one object instance.
Read the full bite: Prototype pollution: how it works and prevention
Question 29 of 30
What trade-off does moving a JWT from localStorage to an HttpOnly cookie introduce?
Show the answer
Answer: a · It blocks JavaScript from reading the token (mitigating XSS theft) but reintroduces CSRF risk needing SameSite and CSRF tokens
HttpOnly hides the token from JavaScript, defeating XSS exfiltration, but auto-sent cookies bring CSRF exposure that must be mitigated. It does not eliminate all risk or remove the need for short token lifetimes.
Read the full bite: JWT storage: localStorage versus HttpOnly cookie
Question 30 of 30
During a zero-downtime restart using cluster module, why must the master stop accepting new connections on old workers before terminating them?
Show the answer
Answer: b · To prevent new requests from landing on workers about to die, ensuring they can drain existing connections cleanly.
The master stops routing new requests to old workers so they can finish their in-flight work without abandoning clients. This prevents the thundering herd problem. Blocking new connections is not automatic; it requires explicit routing changes. Rejecting requests defeats the purpose of zero-downtime. Multiple workers can share a port via clustering.
Read the full bite: How does Node.js cluster module enable zero-downtime restarts?
Could you explain these out loud?
That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.