Easy Common Node.js Interview Questions
1. What is Node.js, and how does it differ fundamentally from a browser's runtime environment?
Node.js is an asynchronous, event-driven JavaScript runtime built on Chrome's V8 engine. While both use V8, the environments differ in their available APIs. Browsers are sandboxed and interact with the DOM and window objects for UI rendering. Node.js relies on C++ bindings (via libuv) to interact with the underlying Operating System, enabling file system access, networking, and process management, making it suitable for backend services.
2. Explain the specific role of the V8 engine within the Node.js architecture.
The V8 engine acts as the compiler and execution unit. It takes JavaScript code, compiles it into native machine code using Just-In-Time (JIT) compilation, and manages the memory heap and call stack. It does not handle the event loop or I/O directly; it delegates those to Libuv and Node.js bindings. Effectively, V8 provides the horsepower for execution, while Node.js provides the API for system interaction.
3. Why is Node.js described as single-threaded, and how does it handle concurrency?
Node.js executes JavaScript on a single main thread, which prevents race conditions common in multi-threaded programming. Concurrency is achieved via the Event Loop and the Libuv C++ library. While the main JS thread is single, Libuv maintains a thread pool (default size 4) to handle heavy operations like File I/O, Cryptography, and DNS lookups in the background, executing the callback on the main thread once the task is complete.
4. How do you instantiate a basic web server using the native HTTP module?
You utilize http.createServer((req, res) => { ... }). While this is fundamental knowledge, in a production environment, we rarely use the raw HTTP module directly due to the boilerplate required for routing and middleware. We typically abstract this using frameworks like Express or Fastify, or place Node behind a reverse proxy like Nginx.
5. Distinguish between blocking and non-blocking code execution in the context of the Event Loop.
Blocking execution halts the Event Loop, preventing it from processing any other incoming requests until the current operation finishes (e.g., fs.readFileSync). Non-blocking execution offloads the operation (usually to the system kernel or thread pool) and accepts a callback/promise, allowing the Event Loop to continue processing other tasks. In Node.js, blocking the loop is the primary cause of performance degradation.
6. How does the CommonJS require() function load modules?
require() is a synchronous operation that reads a JavaScript file, executes it, and returns the module.exports object. Crucially, Node.js caches the module after the first load. Subsequent calls to require() return the cached version, which optimizes performance but means that modules essentially act as singletons within the application process.
7. What is the role of NPM in modern Node.js development?
NPM acts as both the package registry and the CLI for dependency management. Beyond simple installation, it manages the dependency tree and lockfiles (package-lock.json) to ensure deterministic builds across different environments. It also handles semantic versioning resolution to prevent breaking changes when updating libraries.
8. When should you use local versus global package installation?
Local installation (npm install) is the standard for project dependencies to ensure every developer and CI/CD pipeline uses the exact same version defined in package.json. Global installation (-g) should be reserved only for system-wide CLI tools. However, modern best practice often prefers using npx to execute tools without permanently installing them globally.
9. What is the strategic importance of the package.json file?
It is the manifest of the application. It defines metadata, dependencies, and most importantly, scripts. The scripts section serves as the entry point for standardizing development workflows (build, test, lint, start) across the team and CI pipelines.
10. Explain the 'Error-First Callback' pattern.
This was the convention before Promises became standard. A callback function accepts error as the first argument and data as the second. If the operation succeeds, error is null. As a developer, you must always check if (error) return ... immediately. Failing to handle the error allows execution to proceed with undefined data, potentially crashing the application.
11. What problem do Promises solve over traditional callbacks?
Promises mitigate 'Callback Hell' (nested callbacks that grow horizontally) by providing a cleaner chainable API. More importantly, they offer better control flow and error propagation. A Promise represents a future value in one of three states: Pending, Fulfilled, or Rejected, allowing for standardization of async logic.
12. How does async/await utilize Promises under the hood?
async/await is syntactic sugar over Promises and Generators. It allows asynchronous code to be written and read as if it were synchronous. It improves maintainability significantly, but it requires wrapping code in try/catch blocks for error handling, effectively replacing the .catch() method of Promises.
13. How do you interact with the file system using the fs module?
The fs module provides APIs for file manipulation. While it offers synchronous methods, a senior developer should almost always use the asynchronous versions (or fs.promises) to avoid blocking the event loop. For example, fs.readFile handles data buffering, which is fine for small config files but inefficient for large datasets.
14. Compare synchronous and asynchronous file system operations.
Synchronous operations (readFileSync) block the main thread until the disk I/O is complete. This is acceptable during application startup (e.g., reading configs) but catastrophic during request handling. Asynchronous operations delegate the work to the thread pool, ensuring the server remains responsive to other user requests.
15. What is the Buffer class and why is it necessary in Node.js?
JavaScript was designed for strings, not binary data. The Buffer class provides a way to handle raw binary data (streams of integers) directly in memory, allocated outside the V8 garbage-collected heap. This is essential for handling TCP streams, file system operations, and image processing.
16. What are Streams and how do they benefit memory management?
Streams allow reading/writing data piece-by-piece rather than loading the entire dataset into memory. For large files or high-throughput network services, streams are critical. They drastically reduce the RAM footprint of the application and reduce latency by allowing processing to start before the entire file is read.
17. What is the significance of the EventEmitter class?
It is the backbone of Node's event-driven architecture. Many core modules (Stream, Net, HTTP) inherit from EventEmitter. It implements the Observer pattern, allowing objects to subscribe to named events. A critical senior responsibility is managing listeners to prevent memory leaks (e.g., failing to remove listeners on closed connections).
18. Differentiate between process.nextTick() and setImmediate().
The naming is counter-intuitive. process.nextTick() fires immediately after the current operation completes, effectively processing as a microtask before the Event Loop continues. setImmediate() queues the callback to run in the 'Check' phase of the next Event Loop cycle. heavy use of nextTick can starve the I/O loop.
19. How should environment variables be managed in a Node.js project?
Variables are accessed via process.env. In development, we use dotenv to load them from a file. In production, these should never be committed to code; they should be injected by the container orchestrator (Docker/K8s) or a secret manager. Following the 12-Factor App methodology is best practice here.
20. What is middleware in Express.js?
Middleware functions have access to the Request and Response objects and the next function. They form a pipeline. They can execute code, modify the request (e.g., parsing body, adding user info from a token), or end the response cycle. If they don't end the cycle, they must call next() or the request will hang.
21. How are routes defined in Express?
Routes map a URI and HTTP Method to a specific handler function. app.get('/path', handler). For scalable applications, we don't define these on the main app instance but use express.Router to modularize routes by domain or resource.
22. What is the relationship between exports and module.exports?
module.exports is the object that is actually returned by require. exports is simply a reference (alias) to module.exports. If you attach properties to exports, it works fine. However, if you reassign exports (e.g., exports = { ... }), you break the reference, and the module will export nothing (or the default object).
23. What is the REPL and its use case?
Read-Eval-Print Loop. It's an interactive shell useful for quick prototyping, debugging regular expressions, or inspecting the properties of built-in modules without setting up a full project file.
24. How do you debug a Node.js application?
You can use node --inspect to attach Chrome DevTools or use the built-in debugger in IDEs like VS Code. In a production context, however, we rely on structured logging, APM tools (like Datadog or New Relic), and distributed tracing to 'debug' issues post-mortem.
25. Name common built-in Node.js modules.
fs (file system), path (file paths), http (networking), os (operating system info), crypto (encryption), and events (event emitters). Understanding these eliminates the need for redundant npm packages.
26. What is the 'Error-First Callback' convention?
A standard where the first argument of a callback is reserved for the error object (null if successful). This ensures consistent error handling logic across libraries. In modern Node, this is largely superseded by Promises, but legacy libraries still rely on it.
27. What is the Callback Queue (Event Queue)?
It acts as a holding area for callbacks that are ready to be executed. The Event Loop monitors the call stack; when the stack is empty, it dequeues the next callback from the Callback Queue and pushes it onto the stack for execution.
28. How does Node handles multiple concurrent requests given it is single-threaded?
It relies on non-blocking I/O. When a request requires an I/O operation (DB, Network), Node sends that task to the background (system kernel or thread pool) and immediately frees the main thread to handle the next incoming request. When the I/O finishes, the callback re-enters the queue.
29. How do you execute a script?
Via the terminal command node filename.js. In production, this is usually wrapped in a process manager like PM2 or a container entrypoint.
30. What is Control Flow in asynchronous programming?
It refers to the logic governing the order of execution for asynchronous tasks (e.g., serial execution, parallel execution, waterfall). We manage this using Async/Await, Promise.all, or legacy libraries like async.
31. What is Node.js?
Node.js is an open-source, cross-platform JavaScript runtime environment built on Chrome's V8 engine. Unlike a browser, which targets the DOM, Node.js targets the underlying operating system, enabling server-side execution. It utilizes an event-driven, non-blocking I/O model, making it exceptionally efficient for building scalable, data-intensive network applications.
32. What is the primary purpose of Node.js?
Its primary purpose is to build high-throughput, scalable network applications using a single programming language (JavaScript) across the stack. It excels in real-time scenarios (chat apps, live streaming), API gateways, and microservices where handling thousands of concurrent connections with low overhead is critical.
33. What are the core benefits of using Node.js?
- Performance: V8 compiles JS to machine code, and non-blocking I/O prevents thread waiting.
- Unified Stack: Using JavaScript for both frontend and backend enables code reuse (types, validation logic) and simplifies hiring.
- Ecosystem: NPM is the largest software registry in the world.
- Scalability: The event loop model scales well for I/O-bound tasks.
34. Why is Node.js Single-threaded?
It uses a single main thread to avoid the complexity and overhead of thread context switching and race conditions found in multi-threaded environments (like Java/C#). This design choice optimizes for high concurrency in I/O-bound workloads, delegating blocking tasks to the OS kernel or Libuv's thread pool rather than creating a new thread for every request.
35. If Node.js is single-threaded, how does it handle concurrency?
It uses the Event Loop and the Reactor Pattern. When an asynchronous operation (like a DB query) is initiated, Node.js offloads it to the Libuv thread pool or the OS kernel and continues executing the next line of code. When the operation finishes, a callback is placed in the event queue, which the main thread picks up once the call stack is empty.
36. Define 'callback' in Node.js.
A callback is a function passed as an argument to another function, intended to be executed after an asynchronous operation completes. While foundational to Node.js, reliance on raw callbacks often leads to deeply nested code ('Callback Hell'), which is why modern development favors Promises and Async/Await.
37. What is NPM?
NPM (Node Package Manager) is the standard dependency manager for Node.js. It consists of a command-line client (CLI) for installing and publishing packages, and an online database (registry) of public and private packages. It also manages versioning via package.json and lockfiles to ensure environment consistency.
38. What is I/O in the context of Node.js?
I/O (Input/Output) refers to operations involving the transfer of data outside the CPU/memory boundary, such as Network requests, File System access, or Database queries. These are the slowest operations in computing. Node.js is specifically designed to handle these non-synchronously, preventing the CPU from sitting idle while waiting for data.
39. What is the difference between Angular and Node.js?
They operate in completely different contexts. Angular is a client-side (frontend) framework used to build dynamic User Interfaces in the browser. Node.js is a server-side runtime environment used to execute JavaScript on a server (backend). You often use them together: Angular for the UI and Node.js for the API.
40. How many types of API functions are there in Node.js?
There are broadly two types: Asynchronous (Non-blocking), which accept a callback or return a Promise and allow the code to proceed immediately (e.g., fs.readFile); and Synchronous (Blocking), which halt execution until the task finishes (e.g., fs.readFileSync). In production servers, synchronous methods should generally be avoided.
41. Explain Node.js web application architecture.
Node.js typically follows the 'Single Threaded Event Loop' architecture. Clients send requests to the web server. The Event Loop receives these requests. If they involve blocking I/O, they are delegated to the Worker Pool (Libuv). Once processed, the callback returns to the main loop to send the response. This differs from the 'Thread per Request' model of traditional servers.
42. Why is Node.js often favoured over Java or PHP?
Node.js offers superior performance for I/O-heavy workloads due to its non-blocking nature. It allows for a 'Universal JavaScript' stack (frontend + backend), faster development cycles (rapid prototyping), and a massive open-source ecosystem (NPM). However, Java may still be preferred for strictly CPU-intensive computational tasks.
43. What is the difference between front-end and back-end development?
Front-end involves the client-side (what the user sees), focusing on UI/UX, browser compatibility, and DOM manipulation (React, Angular). Back-end involves server-side logic, database management, API design, authentication, and server infrastructure (Node.js, Python, Databases).
44. What is NPM and what role does it play in the ecosystem?
NPM stands for Node Package Manager. It serves two primary roles: it is an online repository for publishing open-source Node.js projects, and it is a command-line utility for interacting with that repository. It allows developers to install, version, and manage dependencies for their projects. It also handles scripts for running tasks like testing, building, and starting applications.
45. What is the fundamental difference between Synchronous and Asynchronous functions in Node.js?
Synchronous functions (blocking) execute sequentially; the program execution halts and waits for the function to return before moving to the next line of code. If a synchronous task takes 5 seconds, the entire application freezes for 5 seconds. Asynchronous functions (non-blocking) initiate a task and return immediately, allowing the code execution to proceed. The result of the asynchronous task is handled later via a callback, promise, or async/await pattern once the task completes.
46. What are the core modules available in Node.js?
Node.js ships with several built-in core modules that provide essential functionality without installing external packages. Key modules include 'fs' (file system operations), 'http' and 'https' (creating servers and making requests), 'path' (handling file paths), 'os' (operating system info), 'events' (handling events), 'stream' (handling data streams), 'crypto' (encryption), and 'util' (utility functions).
47. What is the mechanism and purpose of the 'require' keyword?
The 'require' keyword is part of the CommonJS module system used in Node.js. It allows you to import code (functions, objects, or variables) exported from another file or module. When 'require' is called, Node.js resolves the file path, loads the file, wraps it in a function closure (to keep variables local), executes the code, and caches the exported object. This enables modularity and code reuse.
48. What are the best practices for handling environment variables in Node.js?
Environment variables are handled using the global 'process.env' object. For development and testing, developers typically use the 'dotenv' library to load variables from a '.env' file into process.env. In production, these variables should be injected by the deployment environment (like AWS, Docker, or Kubernetes secrets) rather than committed to code. This keeps sensitive data like API keys and DB credentials secure and allows for configuration changes without code deployment.
49. What is the REPL in Node.js and when would you use it?
REPL stands for Read-Eval-Print Loop. It is an interactive shell environment that comes with Node.js. It reads user input (JavaScript code), evaluates it, prints the result, and loops back waiting for input. It is excellent for quick prototyping, debugging snippets of code, testing libraries, or performing simple calculations without creating a full script file.
50. How do you properly import modules in Node.js (CommonJS vs ES Modules)?
Historically, Node.js used CommonJS: const module = require('module-name');. Modern Node.js (v12+) supports ES Modules (standard in browsers): import module from 'module-name';. To use ES modules, you must either use the .mjs file extension or set "type": "module" in your package.json. It is important to be consistent with the module system chosen for the project.
51. What is the core difference between Node.js and Angular?
Node.js is a backend runtime environment that executes JavaScript on the server-side, allowing access to the file system and database. Angular is a frontend framework (written in TypeScript) that runs in the client's web browser. Node.js handles API logic and database interactions, while Angular handles the user interface and user experience. They are often used together in the MEAN stack.
52. Explain the significance of package.json in a Node.js project.
The package.json file is the manifest of a Node.js project. It holds metadata relevant to the project (name, version, description), manages functional dependencies (packages required to run the app), devDependencies (packages for testing/building), and defines 'scripts' for automating tasks (start, build, test). It ensures that the project is reproducible on other machines via npm install.
53. How do you create a basic HTTP server using the native 'http' module?
You can create a server using the http module: const http = require('http'); const server = http.createServer((req, res) => { res.statusCode = 200; res.end('Hello World'); }); server.listen(3000);. While good for learning, in production, frameworks like Express.js or Fastify are preferred for their routing and middleware capabilities which abstract the boilerplate of the native module.
54. What are some of the most industry-standard libraries used in the Node.js ecosystem?
Common libraries include: Express.js/Fastify/NestJS for web framework/routing; Mongoose/TypeORM/Prisma for database interaction; Passport for authentication; Socket.io for real-time WebSockets; Winston/Morgan for logging; Dotenv for configuration; Jest/Mocha for testing; and Lodash for utility functions.
55. How do you manage dependency lifecycles (install, update, delete) via CLI?
To install: npm install <package> (adds to dependencies) or npm install <package> -D (devDependency). To update: npm update <package> updates to the latest version allowed by semantic versioning rules in package.json. To delete: npm uninstall <package> removes it from node_modules and package.json.
56. Which command allows importing external libraries?
In terms of CLI, npm install <library-name> fetches the library. In code, require('<library-name>') (CommonJS) or import ... from '<library-name>' (ESM) brings the library into the current scope.
57. What is 'Callback Hell' and why is it a problem?
Callback Hell (or the Pyramid of Doom) occurs when multiple asynchronous operations are executed sequentially using nested callbacks. This results in code that drifts heavily to the right, making it difficult to read, debug, and maintain. Error handling becomes duplicated and complex. It is effectively solved using Promises and Async/Await.
58. What are the standard HTTP request methods used in Node.js APIs?
The standard methods correspond to RESTful principles: GET (retrieve data), POST (create data), PUT (replace data entirely), PATCH (update partial data), and DELETE (remove data). Node.js servers handle these methods to route requests to the appropriate logic.
59. What is body-parser and why is it needed in Express.js?
body-parser is a middleware that parses incoming request bodies in a middleware before your handlers, available under the req.body property. Without it, Express receives the raw stream of data but doesn't interpret it as JSON, URL-encoded data, or text. Note: Since Express 4.16.0, body-parser functionality is built-in via express.json() and express.urlencoded().
60. Can you access the DOM in Node.js?
No, you cannot natively access the DOM (Document Object Model) in Node.js. The DOM is a browser-specific API for manipulating HTML documents. Node.js runs on the server (V8 engine) and does not have a window or document object. To parse or manipulate HTML in Node.js, you must use third-party libraries like cheerio or jsdom.
61. How do you manage packages in a Node.js project?
Packages are managed via NPM (or Yarn/PNPM). The package.json file lists the dependencies. npm install downloads them into the node_modules folder. Version locking is handled by package-lock.json to ensure every developer installs the exact same version of every package.
62. What are the two types of API functions in Node.js?
The two types are Asynchronous (Non-blocking) and Synchronous (Blocking) functions. Asynchronous functions (default for I/O) use callbacks/promises and do not block the thread. Synchronous functions (often suffixed with Sync in 'fs' module, e.g., fs.readFileSync) block execution until they complete and are generally used only during startup or scripting, not in request handlers.
63. What packages are commonly used for file uploading in Node.js?
The most common middleware for handling multipart/form-data (file uploads) is Multer. It integrates with Express and handles saving files to disk or memory. Another option is Formidable for parsing form data, or cloud-specific SDKs (like aws-sdk) if uploading directly to S3.
64. How do you connect Node.js to a MongoDB Database?
You typically use the Mongoose ODM (Object Data Modeling) library or the native MongoDB Driver. With Mongoose: mongoose.connect('mongodb://localhost:27017/myapp'). It provides schema definition, validation, and easier data relationship management compared to the raw driver.
65. How do you read command line arguments in Node.js?
Arguments are accessible via the process.argv array. process.argv[0] is the node path, [1] is the script path, and [2] onwards are the user arguments. For complex CLIs, libraries like yargs or commander are used to parse flags and inputs easily.
66. What is an error-first callback?
It is a legacy Node.js convention for asynchronous functions. The first argument of the callback function is reserved for the error object. If the operation fails, this argument contains the error; if it succeeds, it is null, and the subsequent arguments contain the result data. Although Promises and Async/Await are now standard, understanding this is crucial for working with older libraries or wrapping legacy code.
67. How can you avoid 'Callback Hell'?
The primary method is to adopt modern control flow patterns like Promises and Async/Await, which flatten the nesting. Additionally, 'Callback Hell' is often a symptom of poor code structure; it can be mitigated by decomposing complex anonymous callbacks into named, modular functions that handle specific steps of the logic.
68. What are Promises in Node.js?
A Promise is an object representing the eventual completion (or failure) of an asynchronous operation and its resulting value. They provide a cleaner alternative to callbacks, allowing for method chaining (.then()) and better error handling propagation (.catch()). They exist in three states: Pending, Fulfilled, or Rejected.
69. What tools can be used to assure consistent code style, and why is it important?
Tools like ESLint (for code quality/logic errors) and Prettier (for formatting) are standard. Consistency reduces cognitive load when reading code, minimizes git merge conflicts caused by formatting changes, and prevents entire classes of bugs (like unused variables or implicit globals) before code is even run.
70. What is Node.js and how does it fundamentally work?
Node.js is an open-source, cross-platform runtime environment that executes JavaScript code outside of a browser. It works on an event-driven, non-blocking I/O model. It uses the Chrome V8 engine to compile JS to machine code and the Libuv library to handle the Event Loop and asynchronous I/O tasks, allowing it to remain lightweight and efficient for data-intensive real-time applications.
71. What tools can be used to assure consistent code style in a Node.js project?
To ensure consistency and prevent errors, we combine a Linter (like ESLint) to enforce code quality rules (e.g., no unused variables) and a Formatter (like Prettier) to enforce stylistic rules (e.g., indentation, semicolons). These should be integrated into the IDE and the CI/CD pipeline via hooks (like Husky) to reject non-compliant code commits.
72. What is a 'First Class Function' in JavaScript/Node.js?
It means functions are treated like any other variable. You can pass a function as an argument to another function (callback), return a function from another function (closure/factory), and assign a function to a variable. This capability is the foundation of Node.js's asynchronous, callback-based architecture.
73. How do you manage packages and dependencies in a Node.js project?
We use a package manager like npm or Yarn. Dependencies are defined in the package.json file. We differentiate between dependencies (needed for production runtime) and devDependencies (tools for testing/building). A lockfile (package-lock.json or yarn.lock) is crucial to lock down exact versions to ensure reproducible builds across environments.
74. How is Node.js better than traditional thread-based frameworks (like Java/PHP)?
Node.js excels in I/O-heavy workloads. Traditional frameworks often spawn a new thread for every request, which consumes significant RAM and CPU context-switching overhead. Node.js handles thousands of concurrent connections on a single thread using non-blocking I/O, making it much more memory-efficient and faster for applications like streaming, real-time chat, or API gateways.
75. Explain how 'Control Flow' manages function calls in Node.js.
Control flow refers to the logic that dictates the order of execution for asynchronous tasks. Since Node is non-blocking, we can't just list functions line-by-line if they depend on each other. We control the flow using Series (one after another), Parallel (all at once), or Waterfall (output of one is input of next). We implement this using async/await patterns or libraries like async.
76. What are the commonly used timing features in Node.js?
The core timing functions are setTimeout (execute after delay), setInterval (execute repeatedly), setImmediate (execute in the next 'Check' phase of the Event Loop), and process.nextTick (execute immediately after the current operation). We also use console.time() and performance.now() for measuring execution duration.
77. What are the advantages of using Promises instead of Callbacks?
Promises provide better error handling (errors bubble up to a single .catch() block), better readability (avoiding 'Callback Hell' nesting), and improved control flow (chaining via .then()). They also allow for parallel execution management via Promise.all(), which is cumbersome to implement with raw callbacks.
78. Why is Node.js considered single-threaded?
Node.js runs the V8 JavaScript engine on a single main thread. This means only one line of JS executes at a time. However, this is a design choice to avoid complex thread synchronization issues. Under the hood, Node relies on the libuv library, which uses a thread pool (C++ threads) to handle operations like file I/O, effectively making Node asynchronous even if the JS layer is single-threaded.
79. How do you create a simple HTTP server in Node.js?
You use the built-in http module: const http = require('http'); const server = http.createServer((req, res) => { res.end('Hello World'); }); server.listen(3000);.
80. What are the two types of API functions generally found in Node.js?
Node.js APIs generally come in two flavors: Asynchronous (Non-blocking) and Synchronous (Blocking). For example, fs.readFile (async, takes a callback) and fs.readFileSync (sync, returns value). Asynchronous functions are the standard for production code, while synchronous functions are typically used only during startup/initialization.
81. What is the REPL in Node.js?
REPL stands for Read-Eval-Print Loop. It is the interactive shell you get when you run node in the terminal without arguments. It reads JS code, evaluates it, prints the result, and loops back. It is used for quick testing, debugging snippets, or managing a running application.
82. What is the purpose of module.exports?
It encapsulates code. Variables and functions in a Node.js file are private by default. module.exports is the object that is returned when another file requires that module. Whatever you assign to module.exports (an object, a function, a class) becomes the public API of that file.
83. What are the four main types of Node.js Streams?
- Readable: For reading data (e.g.,
fs.createReadStream). 2. Writable: For writing data (e.g.,fs.createWriteStream). 3. Duplex: Can be both read from and written to (e.g., TCP sockets). 4. Transform: Duplex streams that modify data as it passes through (e.g., zlib compression).
84. Which module is used to serve static files in Node.js?
While the native http module can do it manually by reading files and setting headers, in production we typically use Express with express.static('public') or a dedicated package like serve-static. For high performance, we prefer Nginx or a CDN to serve static assets, bypassing Node entirely.
85. What is the use of the underscore _ variable in the REPL session?
In the Node.js REPL, the underscore _ variable stores the result of the previously evaluated expression. It is a convenience feature for quick chaining of operations during interactive testing.
86. What is the default scope of a Node.js application?
The default scope is Local to the Module (File Scope). Variables defined in a file are not global; they are wrapped in a module function wrapper. To make them global (which is bad practice), you must attach them to the global object.
87. What is 'Callback Hell' and how do modern Node.js patterns like Promises and Async/Await resolve it?
Callback Hell occurs when multiple asynchronous operations are nested inside each other, creating a 'pyramid of doom' that is hard to read, debug, and maintain. It also complicates error handling (requiring repetitive if (err) checks). Promises resolve this by flattening the structure into chainable .then() blocks with a single .catch() for errors. Async/Await (syntactic sugar over Promises) further improves this by allowing asynchronous code to be written in a synchronous, top-down style, making control flow clear and allowing standard try/catch blocks for error management.
88. Explain the role of Middleware in Express.js and the 'Chain of Responsibility' pattern.
Middleware functions have access to the request, response, and the next function. They execute sequentially. This implements the Chain of Responsibility pattern: a request passes through a chain of functions (e.g., Logger -> Auth -> BodyParser -> Controller). Each middleware can either modify the request/response and call next() to pass control, or terminate the request by sending a response. Error handling middleware is a special type defined with four arguments (err, req, res, next) and must be placed at the end of the chain.
89. What is the difference between module.exports and exports?
module.exports is the actual object that is returned as the result of a require() call. exports is simply a convenience variable that references module.exports. If you attach properties to exports (e.g., exports.func = ...), it works fine. However, if you reassign exports directly (e.g., exports = { ... }), you break the reference to module.exports, and your module will export an empty object. Always stick to module.exports for clarity and to avoid this common pitfall.
90. What is an EventEmitter in Node.js, and how does it facilitate the Observer pattern?
The EventEmitter class (from the events module) is the core implementation of the Observer pattern in Node.js. It allows objects ('emitters') to emit named events that cause previously registered functions ('listeners') to be called. This decouples the code: the emitter doesn't need to know who is listening, only that an event occurred. This is fundamental to Node.js—server requests, streams, and sockets all inherit from EventEmitter. A senior developer ensures listeners are removed (using .off() or .removeListener()) to prevent memory leaks.
91. What are the 'Global Objects' in Node.js? Name three and their purposes.
Global objects are available in all modules without needing to require() them. 1) global: The Node.js equivalent of window in the browser; variables attached here are accessible everywhere (though this is bad practice). 2) process: Provides information about the current Node.js process (e.g., process.env, process.argv, process.exit()). 3) Buffer: Used to handle binary data. Note that console and setTimeout are also globals. Unlike the browser, variables declared with var at the top level are not added to the global object; they are scoped to the module.
92. What is the purpose of the assert module, and is it suitable for production validation?
The assert module provides a simple set of assertion tests that can be used to test invariants. If an assertion fails (e.g., assert.strictEqual(a, b)), it throws an AssertionError. While useful for internal logic checks and unit testing, it is generally not recommended for validating external user input in production (use libraries like Joi, Zod, or Validator.js instead). assert is designed to crash the process on failure, which is rarely the desired behavior for handling bad user input.
93. Describe the use of the path module. Why should you avoid string concatenation for file paths?
The path module provides utilities for working with file and directory paths. You should always use path.join() or path.resolve() instead of string concatenation (e.g., dir + '/' + file) because operating systems use different path separators (Windows uses \, Linux/macOS use /). The path module automatically handles these OS-specific differences, preventing cross-platform bugs (e.g., 'file not found' errors on Windows deployment).
94. What is the difference between dependencies and devDependencies in package.json?
dependencies are packages required for the application to run in production (e.g., Express, Lodash, Mongoose). devDependencies are only needed during development and testing (e.g., Jest, ESLint, Nodemon). When deploying to production, running npm install --production (or npm ci --omit=dev) will skip installing devDependencies, reducing the size of the node_modules folder and improving security by minimizing the attack surface.
95. What is a REPL in Node.js and how is it used?
REPL stands for Read-Eval-Print Loop. It is an interactive shell that processes Node.js expressions. You access it by typing node in the terminal. It reads your input, evaluates it as JavaScript, prints the result, and loops back to wait for input. It is extremely useful for: 1) Quick prototyping of code snippets, 2) Debugging small logic blocks, and 3) Inspecting the properties of loaded modules without setting up a full project file.
96. What is the primary difference between null and undefined in JavaScript/Node.js?
undefined means a variable has been declared but has not yet been assigned a value; it is the default state. null is an assignment value used to intentionally represent 'no value' or 'empty'. In API design, a field missing from a JSON response is often treated as undefined, whereas a field sent as null explicitly means 'cleared' or 'empty'. typeof undefined is 'undefined', while typeof null is 'object' (a historic JS bug).
97. What are 'LTS' releases of Node.js and why should enterprises use them?
LTS stands for Long-Term Support. Even-numbered versions (e.g., 18, 20, 22) become LTS releases. They are guaranteed to receive critical bug fixes, security updates, and performance patches for 30 months. Odd-numbered releases (e.g., 19, 21) are 'Current' versions with the latest features but a short support lifespan (6 months). Enterprises should always use Active LTS versions to ensure stability, security compliance, and long-term maintainability without the risk of breaking changes found in 'Current' releases.
98. What is the difference between process.exit(0) and process.exit(1)?
These are exit codes sent to the operating system. 0 indicates success—the process finished its task correctly. 1 (or any non-zero number) indicates failure—the process crashed or encountered a fatal error. This is crucial for CI/CD pipelines and container orchestration (like Kubernetes). If a script exits with 1, the pipeline stops or the container restarts. If it exits with 0, the pipeline proceeds. Custom codes (like 137 for Out of Memory) also exist.
99. What are First-Class Functions in JavaScript, and why are they fundamental to Node.js?
A language has First-Class Functions if it treats functions as first-class citizens: they can be assigned to variables, passed as arguments to other functions, and returned from functions. This feature is the foundation of Node.js's asynchronous, event-driven architecture. It allows for the 'Callback Pattern' (passing a function to be executed later) and Higher-Order Functions (like map, filter, or Express middleware) that compose behavior dynamically.
100. Can you access the DOM (Document Object Model) in Node.js? If not, how do you handle HTML parsing?
No, Node.js runs on the V8 engine in a server-side environment, which lacks the window and document objects found in browsers. Accessing document.getElementById will throw a ReferenceError. To parse or manipulate HTML in Node.js (e.g., for web scraping or server-side rendering), you must use third-party libraries like Cheerio (fast, jQuery-like syntax) or JSDOM (which simulates a full browser environment).
101. What distinguishes Node.js from AJAX?
This is a category error comparison. Node.js is a server-side runtime environment for executing JavaScript outside the browser. AJAX (Asynchronous JavaScript and XML) is a client-side technique used in browsers to fetch data from a server without reloading the page. They are often used together: a client uses AJAX to send a request to a Node.js server, but they operate in completely different environments and serve different purposes.
102. What constitutes a 'Blocking' operation in Node.js?
A blocking operation is any execution that forces the Event Loop to pause and wait for a non-JavaScript operation to complete. In Node.js, synchronous methods in the standard library (ending in Sync, like fs.readFileSync or crypto.pbkdf2Sync) are blocking. JSON parsing (JSON.parse) of massive objects is also blocking. These should be avoided in the 'hot path' (request handling) of a server, as they stop the server from handling any other users until the operation finishes.
103. What is the difference between Shallow Copy and Deep Copy in JavaScript?
A Shallow Copy (e.g., Object.assign or Spread ...) copies the top-level properties. If a property is an object, it copies the reference, not the value (changing the nested object in the copy changes the original). A Deep Copy creates a completely independent clone. Historically, we used JSON.parse(JSON.stringify(obj)) (which fails on Dates/Functions). In modern Node.js (v17+), we use the native structuredClone() function for performant, safe deep copying.
104. Explain 'Hoisting' in JavaScript. How do var, let, and const differ regarding it?
Hoisting is the behavior where variable and function declarations are moved to the top of their scope during compilation. Function declarations are fully hoisted (callable before definition). var variables are hoisted but initialized with undefined. let and const are hoisted but placed in a 'Temporal Dead Zone' (TDZ); accessing them before the declaration line throws a ReferenceError. This makes let/const safer and more predictable.
105. What is the difference between Horizontal and Vertical Scaling?
Vertical Scaling (Scaling Up) means adding more power (CPU/RAM) to a single machine. It has a hardware limit and requires downtime to upgrade. Horizontal Scaling (Scaling Out) means adding more machines (nodes) to the pool. Node.js is designed for Horizontal scaling (stateless, small processes). A senior developer designs systems for horizontal scale from day one by avoiding local state and using load balancers.
106. What is the 'Module Wrapper' function in Node.js?
Before executing a module's code, Node.js wraps it in a function wrapper: (function(exports, require, module, __filename, __dirname) { ... }). This provides the module with its scope-local variables (exports, __dirname, etc.) and ensures top-level variables defined in the module do not leak into the global scope. This explains why __dirname is available directly in your code but is not a global object.
107. What is 'Semantic HTML' and does it matter for Node.js SSR (Server Side Rendering)?
Semantic HTML means using tags that convey meaning (<article>, <nav>, <button> vs <div>). In Node.js SSR (e.g., Next.js), generating semantic HTML is critical for SEO (Search Engines understand the structure) and Accessibility (Screen readers rely on it). If your Node.js server sends a soup of divs, search rankings and usability suffer regardless of backend performance.
108. How would you implement a simple 'Health Check' endpoint?
A health check (e.g., /health or /status) should return a 200 OK status. A basic check just returns {status: 'UP'}. A 'Deep' health check (Senior level) also verifies connectivity to dependencies: it pings the Database and checks the Redis connection. If the DB is down, it returns 503 (Service Unavailable). This allows Load Balancers to automatically stop sending traffic to a broken instance.
109. What is the crypto.randomUUID() method?
Introduced in newer Node.js versions, crypto.randomUUID() generates a v4 UUID (Universally Unique Identifier) using a cryptographically secure random number generator. It is much faster and cleaner than importing external libraries like uuid for simple ID generation tasks, reducing dependency bloat.
110. Explain 'Hot Reloading' vs 'Live Reloading' in development.
Live Reloading (e.g., Nodemon) restarts the entire server process when a file changes; state is lost. Hot Reloading (HMR, common in frontend but emerging in backend via Webpack/Vite) replaces only the changed modules without losing application state (like current DB connection or variable values). Live reloading is the standard for Node.js backends due to the complexity of maintaining server state.
111. What is npx and how does it simplify tooling?
npx is a package runner bundled with npm (v5.2+). It allows you to execute binaries from npm packages without installing them globally or locally. Example: npx create-react-app my-app fetches the latest version, runs it, and removes it. This ensures you always use the latest version of a tool and keeps your global namespace clean.
112. Why is String.prototype.replaceAll() preferred over replace()?
Historically, replace('a', 'b') only replaced the first occurrence. To replace all, you had to use Regex: replace(/a/g, 'b'), which is error-prone if the string contains special regex characters. replaceAll() (ES2021) is a native method that replaces all occurrences using standard strings, improving readability and safety.
113. What are the security implications of eval() in Node.js?
eval() executes a string of code. If that string contains user input, an attacker can execute arbitrary commands on your server (Remote Code Execution). It also prevents the V8 engine from optimizing code (de-opts) because the scope is dynamic. There is almost never a valid reason to use eval() in a modern Node.js web application.
114. How do you create a vanilla Node.js server without frameworks?
You use the http core module. The pattern is: const server = http.createServer((req, res) => { ... });. Inside the callback, you inspect req.url and req.method to route requests manually, and use res.writeHead() and res.end() to send responses. While rarely done in production apps (due to the complexity of parsing bodies and routing), knowing this proves you understand the 'metal' beneath Express or NestJS.
115. What is the detailed difference between Frontend and Backend development in a Node.js context?
Frontend (Client-side) involves code running in the user's browser (React, HTML, CSS), focusing on UI/UX, DOM manipulation, and network calls. Backend (Server-side Node.js) involves code running on the server, focusing on business logic, database interactions, API security, file systems, and authentication. With 'Universal JavaScript' (Next.js/Nuxt), this line blurs, as Node.js can render the frontend HTML on the server (SSR) before sending it to the client.
116. Does Node.js support Multi-core systems by default?
No, not by default. A standard Node.js application runs on a single thread and utilizes only one CPU core, regardless of how many cores the server has. To utilize multi-core systems, you must explicitly use the cluster module to fork processes or use a Process Manager like PM2 to run multiple instances of your application.
117. What is the primary usage of the url module in Node.js?
The url module is used for URL resolution and parsing. It splits a web address into readable parts: host, pathname, query parameters, and protocol. Modern Node.js (v10+) uses the WHATWG URL API (global URL class) which is compatible with browsers: const myUrl = new URL('https://example.com?id=5');. This is preferred over the legacy url.parse() method.
118. What is npm init and what does it generate?
npm init is a command-line utility that sets up a new Node.js project. It prompts the user for project details (name, version, entry point, test command, git repository) and generates a package.json file based on those answers. You can use npm init -y (or --yes) to skip the questionnaire and generate a default file instantly.
119. How do you update a specific dependency to the latest version?
You can run npm install <package-name>@latest. This fetches the latest version from the registry and updates your package.json and package-lock.json accordingly. To update all packages to their latest major versions (potentially breaking changes), you might use a tool like npm-check-updates (ncu) as the standard npm update respects the semantic versioning ranges (usually preventing major bumps).
120. What is the purpose of the .exports property on the module object?
module.exports is the object that is returned when another file requires your module. Whatever you assign to module.exports (an object, function, or class) becomes the public interface of that file. It is the mechanism that enables modularity in Node.js.
121. Can you use Node.js for Frontend Development?
Node.js itself is a runtime for the server. However, the tools used for Frontend Development (like Webpack, Vite, React scripts, TypeScript compilers, and CSS preprocessors) run on Node.js. So while Node.js code doesn't typically run in the browser (users' screens), the development environment and build pipeline for frontend apps are almost entirely powered by Node.js.
122. Explain the architecture of Node.js and the specific use cases where it excels compared to traditional multi-threaded environments.
Node.js is built on the V8 JavaScript engine and utilizes a single-threaded, non-blocking I/O model driven by an event loop. Unlike traditional multi-threaded environments (like Java or C# web servers) that spawn a new thread for every request, Node.js handles concurrent connections on a single thread using asynchronous callbacks. This makes it highly memory efficient and performant for I/O-bound tasks, such as real-time applications (chat, sockets), streaming services, and REST APIs. However, it is generally ill-suited for CPU-intensive tasks (like image processing or complex calculations) because long-running computations block the event loop, freezing the server for all clients.
123. How do you mitigate 'Callback Hell' in modern Node.js applications?
Callback Hell (deeply nested callbacks making code unreadable and hard to debug) is mitigated primarily through modern asynchronous patterns. 1) Promises: Flattening the structure by chaining .then() blocks. 2) Async/Await: The industry standard in modern Node.js, allowing asynchronous code to be written in a synchronous, linear style using try/catch blocks for error handling. 3) Modularization: Breaking complex logic into smaller, standalone functions. Libraries like async.js were used historically, but native Async/Await is now the preferred approach.
124. Explain the concept of Middleware in Node.js (specifically within frameworks like Express) and the 'Chain of Responsibility' pattern.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. They effectively implement the Chain of Responsibility pattern. Middleware can execute code, modify the request and response objects, end the request-response cycle, or call next() to pass control to the next middleware. Common uses include logging, body parsing, authentication/authorization checks, and error handling. If the current middleware does not end the cycle, it must call next(), otherwise, the request will hang.
125. What are the best practices for managing dependencies and packages in a production Node.js project?
Dependency management relies on npm, yarn, or pnpm. Best practices include: 1) Always committing the lock file (package-lock.json or yarn.lock) to ensure deterministic builds across environments. 2) Separating dependencies (runtime) from devDependencies (build/test). 3) Using Semantic Versioning (SemVer) correctly (understanding caret ^ vs tilde ~). 4) Regularly auditing packages for security vulnerabilities using npm audit. 5) Using npm ci (clean install) in CI/CD pipelines to strictly install dependencies from the lock file, ensuring consistency.
126. How should sensitive configuration and Environment Variables be handled in a Node.js application following the 12-Factor App methodology?
Configuration should be strictly separated from code. We use environment variables (accessed via process.env) to handle sensitive data like API keys, database URLs, and port numbers. In development, tools like dotenv load these from a .env file (which must be .gitignore'd). In production, these variables should be injected by the orchestration platform (like Kubernetes, AWS Secrets Manager, or Docker Compose). Hardcoding secrets in the source code is a critical security vulnerability and violates the 12-Factor App methodology.
127. Identify key Node.js Core Modules and describe a scenario where you would use fs and events.
Core modules allow Node to function without external dependencies. Key modules include http (server), fs (file system), path (file paths), os (operating system info), and events (event emitters).
Scenario: You might use fs to read a log file stream, and the events module (specifically EventEmitter) to create a custom logger class that emits a 'log' event whenever a new line is written. This decouples the writing logic from the logic that might want to react to a log (like sending an alert).
128. What are Global Objects in Node.js, and how does the scope of global differ from the window object in browsers?
Global objects are available in all modules without importing. Examples include process, Buffer, console, setTimeout. In browsers, the top-level scope is the window object, and variables declared with var in the global scope attach to it. In Node.js, the top-level object is global. However, variables declared in a Node.js file (module) are not added to global but are scoped to that specific module. Additionally, variables like __dirname, __filename, exports, and module appear global but are actually arguments wrapped around every module execution.
129. Demonstrate how to create a basic HTTP server using the native Node.js http module without frameworks.
While frameworks like Express are common, understanding the native module is vital.
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/' && req.method === 'GET') {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({ message: 'Hello World' }));
} else {
res.writeHead(404);
res.end();
}
});
server.listen(3000);This demonstrates the raw request/response handling that frameworks abstract away.
130. Explain the 'Error-First Callback' pattern and why it was the standard convention in Node.js.
The Error-First Callback pattern is a convention where a callback function accepts error as the first argument and the result as the second (e.g., (err, data) => ...). If the operation fails, err is populated; if it succeeds, err is null. This forces the developer to check for errors before processing data. While Promises and Async/Await have largely replaced this in application code, many native Node.js APIs (like fs.readFile) still use this pattern to maintain backward compatibility.
131. How do you debug a Node.js application effectively beyond using console.log?
Professional debugging involves using the Node.js Inspector. You can start Node with the --inspect or --inspect-brk flag. This allows you to attach a debugger, such as Chrome DevTools or the VS Code debugger, to the running process. This enables setting breakpoints, stepping through code, inspecting the call stack, watching variable values in real-time, and profiling memory usage to find leaks. Relying solely on console.log is inefficient for complex logic or race conditions.
132. Why is Express.js the dominant framework for Node.js, and how does it facilitate REST API development?
Express is a minimal, unopinionated web framework that provides a robust set of features for web and mobile applications. It abstracts the low-level http module, offering an easy interface for routing (mapping URLs to functions), middleware integration (for parsing, auth, logging), and template rendering. Its dominance comes from its simplicity and the massive ecosystem of middleware packages available. For REST APIs, it simplifies handling HTTP verbs (app.get, app.post) and managing JSON responses, allowing developers to structure applications quickly without enforcing a strict architecture.
Last updated on