As a technology expert who's undergone dozens of interviews, I decided to share some tricky Node.js questions that tend to catch even the most seasoned developers off guard. Whether you're gearing up for a Node.js interview or want to gain more insight into Node's architecture, the following questions will put your knowledge to the test in numerous important areas.
Core Concepts & Architecture
- Describe the difference between
process.nextTick()andsetImmediate(). Which one gets run first and why?
- Answer:
process.nextTick()gets run before the event loop resumes, whereassetImmediate()gets run in the Check phase of the event loop.process.nextTick()gets run first, even ahead of I/O events and timers, so it is good for deferring execution until the next iteration of the event loop, but with priority.
2. What does Node.js do when it finds an uncaught exception? How do you handle such situations?
- Answer: When an uncaught exception happens, Node.js will output the error message and kill the process. In order to handle this, you can use
process.on('uncaughtException'), but a better practice is to catch errors withtry-catchanddeal with them accordingly using event listeners or a custom error handler.
3. Explain the Event Loop in Node.js and its stages in the proper order of execution.
Answer: The Event Loop includes the following stages:
- Timers: Executes scheduled timers (
setTimeout,setInterval). - I/O callbacks: Runs callbacks for I/O operations.
- Idle, prepare: Internal stage for Node.js maintenance.
- Poll: Reads new I/O events (most of the work occurs here).
- Check: Runs
setImmediate()callbacks. - Close callbacks: Runs
closeevent listeners.
4. What's the difference between Worker Threads and Child Processes in Node.js? When would you prefer one over the other?
- Answer: Worker Threads are for CPU-bound operations within the same Node.js process (able to share memory). Child Processes are separate Node.js runs with their own memory. Use Worker Threads for concurrent computation within the same process and Child Processes for things that can be fully isolated.
5. How does Node.js support CPU-bound work even though it's single-threaded?
- Answer: Node.js uses the Event Loop to deal with asynchronous I/O. For CPU-bound work, you can offload work onto Worker Threads or Child Processes, which execute concurrently and won't block the event loop.
6. Describe the difference between readFile vs createReadStream in the fs module. When would you use either?
- Answer:
readFilereads the whole file into memory, which is appropriate for smaller files.createReadStreamreads the file in pieces and is more appropriate for big files because it enables you to process data while it is being read, without having to load everything into memory.
7. What really happens when we run require('module') in a Node.js application?
Answer: When require() is invoked , Node.js:
- Resolves the module path.
- Loads the module if it's not already loaded (caches it).
- Runs the module code within a function wrapper (an IIFE).
- Returns the exports object of the module.
8. What is Libuv and what role does it play in Node.js architecture?
- Answer: Libuv is a C library that gives asynchronous I/O support, event loops, and thread pools to Node.js. It abstracts I/O operations (such as file system and network) on various platforms and offers efficient non-blocking I/O.
Memory Management & Performance
- How do you diagnose and solve memory leaks in a Node.js application?
- Answer: Utilize Node.js heap snapshots via Chrome DevTools or clinic.js to detect memory leaks. Check for retained objects or increased memory usage over time. Solve leaks by removing unnecessary references and proper cleanup of resources.
2. What is the significance of the --max-old-space-size flag in Node.js?
- Answer: This flag determines the maximum amount of memory granted to the V8 heap. It prevents out-of-memory issues such as OutOfMemoryError when the default limit is reached, particularly for large-sized applications.
3. Describe the differences between Buffer and ArrayBuffer in Node.js.
- Answer:
Bufferis Node.js-specific, intended for use in operating on binary data in I/O operations. ArrayBuffer is a generic JavaScript object available in typed arrays to operate on raw binary data in the browser or Node.js with a less comprehensive API.
4. What techniques would you use to make a Node.js application stateless?
- Answer: To stateless an app, implement JWT tokens or OAuth for authenticating users, cache session information in a distributed cache (e.g., Redis), and do not cache user data on the server across requests.
5. Explain what V8 hidden classes are and how they affect performance.
- Answer: V8 Hidden Classes are V8 engine internal data structures that optimize object property access. When an object's structure is dynamically changing (e.g., properties are added), it can result in hidden class transitions, which can affect performance in a negative way.
6. How can you implement graceful shutdown in a Node.js server?
- Answer: Listen for SIGINT (Ctrl+C) or SIGTERM signals, drain all current connections, and complete ongoing requests before the server exits.
- Example:
process.on('SIGINT', () => { server.close(() => { console.log('Server closed'); process.exit(0); }); });
Asynchronous Programming
- Describe Promises, Async/Await, and Callbacks. How are they different? What are their edge cases?
- Answer:
- Callbacks are easy to use but result in callback hell.
- Promises have a more elegant approach to asynchronous operations with chaining (
.then(),.catch()). - Async/Await makes Promises easier with synchronous-style code and error handling (
try/catch). - Edge cases: async/await and Promises are easier to read, but both can still have unhandled rejections if not properly handled.
2. What is Promise.all() and under what circumstances can it cause problems in your application?
- Answer:
Promise.all()runs multiple promises concurrently and resolves when all promises are successful. It causes problems when one promise fails because it rejects at once and doesn't wait for the remaining ones.
3. Describe the concept of error-first callbacks in Node.js. Why is this pattern used?
- Answer: In error-first callbacks, the error (if any) is always given as the first parameter and the result as the second. Error handling is made easy with this design, and it enables asynchronous functions to indicate both success and failure.
4. What does rejecting a Promise without a catch handler?
- Answer: If a Promise is rejected and there is no catch handler, it results in an unhandled promise rejection, which may crash the application in later versions of Node.js or result in unhandled errors.
5. What's different about how async/await handles erroring compared to the traditional Promise chains?
- Answer: Errors in async/await are handled in try/catch blocks, which makes them more natural than traditional .then().catch() Promise chains.
Security & Best Practices
- What are the most frequent security flaws in Node.js applications and how would you prevent them?
- Answer: Frequent flaws are SQL injection, cross-site scripting (XSS), cross-site request forgery (CSRF), unsafe dependencies, and input validation. Prevent using prepared statements, escaping outputs, dependency scanning utilities, and validating inputs.
2. Describe how you would apply proper rate limiting in a Node.js API.
- Answer: Store request counts using Redis and establish an upper bound on requests per user in a time window. Create middleware to test the rate limit and, if within, allow the request or reject it otherwise.
3. How would you securely store API keys and secrets in a Node.js application?
- Answer: Use environment variables (e.g.,
.envfiles) and avoid hardcoding secrets. Store sensitive keys in Vault, AWS Secrets Manager, or a similar tool for secure key management.
4. What is prototype pollution in Node.js and how can it be prevented?
- Answer: Prototype pollution occurs when an attacker modifies an object's prototype, potentially leading to malicious behavior. Prevent this by sanitizing input and using libraries that handle object manipulation securely.
5. How do you validate and refresh JWT tokens in a Node.js application?
- Answer: Authenticate the JWT signature and payload against a secret key. Token refreshing can be done by returning a new token when the existing one is near expiration, commonly by checking the refresh token against a saved value.
Advanced Topics
- Describe the need and operations of the Node.js cluster module. What are its shortcomings?
- Answer: The cluster module enables you to spawn child processes (workers) in order to utilize multi-core systems. It has limitations around shared state management between workers and will need a load balancer to actually share traffic.
2. How do streams work in Node.js? Describe backpressure and how you would handle it.
- Answer: Streams enable reading and writing of data sequentially in pieces. Backpressure arises when the writable stream is saturated. Manage backpressure by applying the pause/resume methods to manage the flow of data.
3. What are Node.js ESM modules? How do they differ from CommonJS modules?
- Answer: ESM (ECMAScript Modules) is the native module system for JavaScript, via
import/export. CommonJS employsrequire()andmodule.exports. ESM supports asynchronous loading and is native support in the latest versions of Node.js.
4. How does the Node.js debugger work? Describe how you would debug memory issues.
- Answer: Utilize the built-in Node.js debugger or Chrome DevTools to place breakpoints, view variables, and step through the code. For memory-related issues, examine heap snapshots, search for retained objects, and employ tools such as clinic.js or heapdump.
5. Describe the purpose of the vmmodule in Node.js and when you would use it.
- Answer: The
vmmodule enables you to execute JavaScript code in Node.js inside a sandboxed environment. Use it to evaluate code, such as executing dynamic scripts, or for security (e.g., in controlled environments).
6. How would you optimize a Node.js application for production deployment?
- Answer: Optimize through application of clustering on multi-core, allowing gzip compression for responses, implementation of a reverse proxy (e.g., Nginx), reduction of unnecessary dependencies, implementation of caching, and implementation of correct error handling and monitoring strategies.
Final Thoughts:
These tricky Node.js interview questions cover everything from the basics of the event loop to advanced concepts like clusters, streams, and memory management. They're designed to test your practical experience as well as your problem-solving skills when working with Node.js in production environments.
Good luck preparing for your interview!
If you found this post insightful or inspiring, consider fueling my next one with a coffee ☕ — your support means the world. [link]