Top 30 Node.js Interview Questions and Answers
30 multiple-choice questions on Node.js, drawn from 30 bites out of the 42 tagged Node.js on Tezvyn. 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.
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
Why did moving the apps into workspace packages under services/* initially break production?
Show the answer
Answer: c · Node enforced package boundaries, exposing invalid import aliases and hardcoded paths that assumed the old root-relative layout
Node began enforcing package boundaries after the move, so an import alias that reached outside the services/site boundary failed with ERR_INVALID_PACKAGE_TARGET and a hardcoded MDX fetch path pointed to the wrong location. Option D is tempting because lockfile consolidation produced most of the diff, but the outage was caused by path assumptions, not dependency conflicts.
Read the full bite: Kent C. Dodds Fixes Accidental Monorepo with Workspaces
Question 2 of 30
What is the primary benefit of splitting a CPU-intensive synchronous operation into smaller pieces using setTimeout(fn, 0)?
Show the answer
Answer: b · To allow the browser to process UI updates and user input between task segments.
The card states that splitting work with setTimeout(fn, 0) allows yielding control back to the event loop, enabling the browser to process user input and render updates, keeping the UI alive. Option A is incorrect because this technique adds overhead and does not necessarily speed up the overall execution time; its purpose is responsiveness, not raw speed.
Read the full bite: JavaScript's Event Loop: Macrotasks & Microtasks
Question 3 of 30
For which task would Node.js Worker Threads provide the most significant benefit?
Show the answer
Answer: c · Processing a large video file to apply a filter.
Worker threads are specifically designed for CPU-bound operations like video processing to offload heavy computation from the main thread. I/O-bound tasks, such as database queries or network requests, are already efficiently managed by Node's event loop and do not benefit from worker threads.
Read the full bite: Worker Threads: True Parallelism in Node.js
Question 4 of 30
What is the primary characteristic that distinguishes the Service Layer from the Web Layer?
Show the answer
Answer: d · It contains the core business logic, independent of HTTP specifics.
The card explicitly states the Service Layer "contains the core business logic, orchestrating tasks without knowing about HTTP," highlighting its independence from the web protocol. Option B describes the primary function of the Web Layer, which is concerned with HTTP requests and responses.
Read the full bite: Structuring Express Apps with Layered Architecture
Question 5 of 30
When is it inappropriate to use a callback in Node.js?
Show the answer
Answer: a · When you must have a result before the next line runs
The card explicitly warns against using callbacks when you need a result immediately before moving on, because they are designed for deferred, non-blocking execution. The other three options are all I/O scenarios where callbacks are the recommended pattern.
Read the full bite: Node.js Callbacks: Functions That Run Later
Question 6 of 30
In JavaScript's single-threaded environment, what is the main problem Promises are designed to address?
Show the answer
Answer: a · To prevent the user interface from freezing during network requests or file I/O.
Promises were created to manage asynchronous operations gracefully, allowing other code to run without blocking the main thread, which prevents the user interface from freezing during long-running tasks like network requests. Option C is incorrect because JavaScript remains single-threaded; Promises manage non-blocking I/O, not true parallel CPU execution.
Read the full bite: JavaScript Promises: Handling Future Values
Question 7 of 30
What is the fundamental mechanism by which Promise.then() enables sequential asynchronous operations?
Show the answer
Answer: a · Each call to .then() returns a new promise, whose resolution depends on the preceding handler's outcome.
The core mechanism for chaining is that every .then() call creates and returns a new promise, allowing the next step in the sequence to wait for the previous one's resolution. Option C describes the outcome but not the underlying mechanism of how this sequential execution is achieved. Option B describes a common misconception where multiple handlers attached to the *same* promise execute in parallel, not sequentially.
Read the full bite: Promise.then(): Each Call Returns a New Promise
Question 8 of 30
When an await keyword is encountered inside an async function, what is its primary effect?
Show the answer
Answer: d · It pauses the execution of the async function, allowing other tasks to run, and resumes when the Promise settles.
The card explains that await acts as a 'pause and resume' button for the async function, allowing the JavaScript engine to do other work while the Promise settles, thus ensuring non-blocking behavior. Option C describes a blocking scenario, which async/await is designed to prevent.
Read the full bite: Async/Await: Write Non-Blocking Code That Reads Synchronously
Question 9 of 30
What is the immediate outcome when one of the promises provided to Promise.all() rejects?
Show the answer
Answer: c · The Promise.all() promise immediately rejects with the reason of the first failed promise.
Promise.all() has a 'fail-fast' behavior: if any single input promise rejects, the entire Promise.all() promise immediately rejects with the reason of that first failed promise. Option A describes the behavior of Promise.allSettled(), which waits for all promises to settle regardless of their outcome.
Read the full bite: Promise.all(): Wait for Multiple Promises at Once
Question 10 of 30
When using Promise.race() for a network request with a timeout, what is the outcome if the timeout promise rejects before the network request resolves?
Show the answer
Answer: d · The Promise.race() promise will reject with the timeout's error.
Promise.race() settles with the outcome of the very first promise to settle, regardless of whether it resolves or rejects. If the timeout promise rejects first, the race() promise immediately rejects with that error. The network request's eventual resolution is ignored because it was not the first to settle.
Read the full bite: Promise.race(): First Promise to Settle Wins
Question 11 of 30
What is the primary reason to use Promise.allSettled() over Promise.all() for multiple asynchronous tasks?
Show the answer
Answer: a · To obtain a status report for every task, allowing individual handling of successes and failures.
Promise.allSettled() is designed to provide an outcome for every promise in the batch, whether it fulfilled or rejected, allowing for graceful handling of partial failures. Option C describes Promise.all(), which short-circuits and rejects the entire batch if any promise fails.
Read the full bite: Promise.allSettled(): Never Fail a Batch of Promises
Question 12 of 30
Which scenario best describes when to use Promise.any()?
Show the answer
Answer: d · To retrieve the result from the first promise that successfully completes, ignoring any failures.
The correct answer (D) accurately describes Promise.any()'s purpose: to get the first successful result, even if other promises fail. Option C describes Promise.race(), which settles with the first promise regardless of its outcome.
Read the full bite: Promise.any(): Get the Fastest Successful Result
Question 13 of 30
How does Top-Level Await primarily affect the loading and execution of an ES module and its dependencies?
Show the answer
Answer: a · It pauses the execution of the specific module and any modules that depend on it until the top-level promise resolves.
The card states that Top-Level Await "pauses the execution of that specific module" and that "When another module imports it, the JavaScript engine effectively 'awaits' the completion of the module being imported." This means dependent modules will wait. Option C is incorrect because the card explicitly states, "it does not block the main thread for other unrelated tasks."
Read the full bite: Top-Level Await: `await` Without an `async` Function
Question 14 of 30
Which action is crucial for a Node.js HTTP server to signal that a response has been fully sent to the client?
Show the answer
Answer: c · Invoking response.end() on the response object.
The card explicitly states that `response.end()` is critical to signal that the response is complete, otherwise the client will hang indefinitely. While `response.write()` sends data, it does not close the connection or mark the response as finished.
Question 15 of 30
Under which circumstance would directly using __dirname in a Node.js script result in a ReferenceError?
Show the answer
Answer: b · The Node.js project is configured to use ES Module syntax (e.g., import/export).
The card explicitly states that __dirname does not exist in ES Modules, and attempting to use it in such a context will cause a ReferenceError. Other options describe scenarios that are either the problem __dirname solves or unrelated to its availability.
Read the full bite: __dirname and __filename: Path Anchors in Node.js
Question 16 of 30
Which task is the Node.js os module primarily designed to help with?
Show the answer
Answer: d · Querying the host system's hardware and operating system details.
The os module is designed for querying static system properties and environment details like CPU cores, memory, and platform type. Tasks like managing environment variables, path manipulation, or interacting with the Node.js process itself are handled by other modules like process or path.
Read the full bite: Node.js os Module: Reading Your System's Vital Signs
Question 17 of 30
What is the primary security risk when using algorithms like MD5 or SHA1 for sensitive data hashing?
Show the answer
Answer: a · They are susceptible to collision attacks, where distinct inputs yield identical hash values.
The card explicitly states that MD5 and SHA1 are vulnerable to 'collision attacks,' where two different inputs can produce the same hash, undermining their reliability. Hashing is a one-way process by design, so it cannot be reversed to retrieve original data, making option D incorrect for any hashing algorithm.
Read the full bite: Hashing Data with Node.js's `crypto` Module
Question 18 of 30
What is the primary negative consequence of 'Callback Hell' in JavaScript?
Show the answer
Answer: b · It results in deeply nested, unreadable code that is difficult to maintain.
Callback Hell's core problem is the 'pyramid of doom' structure, leading to deeply indented code that is 'notoriously difficult to read and maintain.' It does not block the application; JavaScript's asynchronous model prevents that.
Read the full bite: Callback Hell: Navigating JavaScript's Async Pyramid
Question 19 of 30
Which scenario is most likely to cause a functional issue immediately after adding app.use(helmet()) to an Express app without further configuration?
Show the answer
Answer: d · The application loads scripts or styles from external domains like CDNs.
The default Content-Security-Policy (CSP) in Helmet is very strict, only allowing resources from the same origin ('self'). This will block common external resources like scripts from CDNs or Google Fonts, causing functional issues until the CSP is explicitly configured. While running without HTTPS can cause issues with 'upgrade-insecure-requests', the card highlights CSP configuration for external resources as the primary and most common 'footgun'.
Read the full bite: Helmet.js: Secure Express Apps with HTTP Headers
Question 20 of 30
Which change to an API would most likely necessitate creating a new version?
Show the answer
Answer: d · Splitting a single 'address' field into 'street', 'city', and 'zipCode' fields.
The card states that 'breaking changes' alter data structures or endpoint behavior, citing splitting a 'fullName' field as an example. Splitting an 'address' field is analogous, requiring clients to adapt to new fields. Adding optional fields or new endpoints are non-breaking changes, and performance optimizations do not alter the API contract.
Read the full bite: API Versioning: Managing Change Without Breaking Clients
Question 21 of 30
Given its synchronous API and embedded design, which workload is node:sqlite best suited for?
Show the answer
Answer: c · A local CLI utility that logs events to a file without extra npm dependencies
node:sqlite is designed for lightweight, local structured storage such as CLI tools that avoid external dependencies, whereas a high-traffic API is a poor fit because DatabaseSync executes synchronously and blocks the event loop.
Question 22 of 30
In an error-first callback, what is the specific purpose of the very first argument?
Show the answer
Answer: d · To signal the presence of an error or the successful completion of the task.
The card states that the first parameter is "always an Error object (or null if no error occurred)," which means it signals whether an error occurred or if the task completed successfully. Option C is incorrect because successful data is passed in subsequent arguments, not the first.
Read the full bite: Error-First Callbacks: Node.js's Original Async Handler
Question 23 of 30
What is the primary benefit of implementing custom error classes in an application, especially for APIs?
Show the answer
Answer: d · They allow for reliable, type-based differentiation of failure modes, enabling specific responses.
The card emphasizes that custom error classes provide explicit, typed categories for failures, allowing consuming code (like API middleware) to reliably differentiate between various failure types (e.g., using 'instanceof') and send appropriate responses. While preventing crashes is a goal of error handling, it's not the primary, unique benefit of *custom* error classes over generic ones, which also allow for caught errors.
Read the full bite: Custom Error Classes: Beyond Generic Errors
Question 24 of 30
What is the fundamental benefit of using Joi for data validation over writing custom imperative checks?
Show the answer
Answer: c · It enables a declarative approach to defining data structures, enhancing readability and maintainability.
Joi's primary advantage is replacing error-prone, repetitive imperative validation with a readable, declarative schema that acts as a blueprint for data. Option D is incorrect because the card explicitly states Joi is for validation, not sanitization against attacks like XSS.
Read the full bite: Joi: Declarative Schemas for Data Validation
Question 25 of 30
What is Supertest's core mechanism for simplifying Node.js API testing?
Show the answer
Answer: a · It provides an in-memory simulation of the HTTP request-response cycle.
Supertest simplifies API testing by simulating the entire HTTP request-response cycle directly in-memory, interacting with the application's router. Option D is incorrect because Supertest's primary goal is to avoid the boilerplate of managing separate server processes, operating in-process instead.
Read the full bite: Supertest: Test Node.js APIs Without the Boilerplate
Question 26 of 30
When would you use a Mock over a Stub or Spy?
Show the answer
Answer: a · When you need to verify that a specific interaction with a dependency occurred as expected.
Mocks are specifically used for verifying interactions with dependencies, often with pre-defined expectations about how they should be called. While Spies also record calls for later inspection, Mocks are designed for direct verification of expected interactions, making option A the correct choice. Option B describes the primary use case for a Spy.
Question 27 of 30
Which characteristic is the primary reason for advocating a limited and strategic use of End-to-End (E2E) tests?
Show the answer
Answer: a · Their execution is slow, they can be brittle, and debugging failures is complex.
The card explicitly states that E2E tests are slow to run, can be flaky, and are difficult to debug, making them unsuitable for widespread use. While E2E tests involve the UI, their main purpose is to verify the entire integrated system, not individual UI components.
Read the full bite: E2E Testing: The Final Check, Not The Whole Strategy
Question 28 of 30
Why should you copy package.json before copying the rest of the app code in a Dockerfile?
Show the answer
Answer: d · It allows Docker to cache the dependency layer; if only app code changes, dependencies are not reinstalled.
Docker layer caching works by matching command inputs. If package.json hasn't changed, the RUN npm ci layer is cached and reused. Copying all code first would invalidate the cache on any code change, forcing a full reinstall every time. This separation optimizes build speed dramatically.
Read the full bite: What are key Dockerfile steps for Node.js Express apps?
Question 29 of 30
Why is it critical that output encoding for XSS prevention is context-aware?
Show the answer
Answer: c · Different output locations (like HTML body vs. script tag) interpret special characters differently.
The correct answer is B because browsers interpret special characters differently depending on whether they are in an HTML tag, an attribute, or a script block, requiring specific encoding for each context. Option D is a common misconception, as encoding modifies characters to prevent execution, not to preserve their literal form if it's malicious.
Read the full bite: XSS Prevention: Context-Aware Output Encoding
Question 30 of 30
Which practice primarily prevents sensitive API keys from being accidentally exposed via version control in a Node.js application?
Show the answer
Answer: b · Storing them in a .env file and ensuring .env is listed in .gitignore.
Storing sensitive data like API keys in a .env file and excluding it from version control via .gitignore is the recommended method to prevent accidental exposure, as highlighted in the canonical example. Encrypting keys within source files (D) or hashing them (A) does not prevent their initial exposure if the files are committed, and hashing is typically for passwords. Disabling verbose error messages (C) prevents information leakage but not exposure of secrets in version control.
Read the full bite: Preventing Sensitive Data Exposure in Node.js
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.