Node Interview - Basic
What is Node.js? Explain its main features and advantages/benefits.
Node.js is an open-source, cross-platform runtime environment that allows you to run JavaScript code on the server side. It is built on Chrome's V8 JavaScript engine and enables developers to use JavaScript to write server-side applications, rather than being limited to client-side scripting.
i) Main Features of Node.js
a) Asynchronous and Event-Driven
Node.js uses a non-blocking I/O model, meaning operations like reading from a database or file don’t block the execution of other code.
It uses an event loop to handle multiple requests simultaneously, making it highly scalable.
b) Single-Threaded but Highly Scalable
It uses a single-threaded event loop architecture, which is more efficient than traditional multi-threaded models for I/O-heavy operations.
c) Fast Execution
Built on the V8 engine, Node.js compiles JavaScript into machine code, making execution very fast.
d) NPM (Node Package Manager)
Comes with a vast library of open-source packages and tools, making development faster and easier.
e) Cross-Platform
Runs on multiple platforms including Windows, Linux, and macOS.
f) Real-Time Capabilities
Perfect for building real-time applications like chat apps or collaborative tools due to WebSocket support.
g) No Buffering
Streams data rather than buffering it, which is particularly useful for real-time audio/video streaming applications.
2) Advantages / Benefits of Node.js
a) High Performance
Thanks to V8 and asynchronous handling, Node.js delivers great speed and performance.
b) Efficient for I/O-heavy Applications
Especially suitable for applications that involve lots of disk or network access (e.g., APIs, file servers).
c) Single Language for Frontend and Backend
Developers can write both client-side and server-side code in JavaScript, improving productivity and code sharing.
d) Large and Active Community
A rich ecosystem of modules and a supportive developer community help solve problems and accelerate development.
e) Microservices-Friendly
Lightweight and modular, making it suitable for microservices architectures and serverless applications.
f) Easy to Learn for JavaScript Developers
Front-end developers can transition to backend development without learning a new language.
3) Common Use Cases of Node.js
a) RESTful APIs and backend servicesb) Real-time chat applications
c) Streaming services
d) Serverless and microservices architecture
e) IoT (Internet of Things) applications
Explain how does Node.js work?
Node.js works on a single-threaded, event-driven architecture that is particularly well-suited for building non-blocking, I/O-intensive applications like web servers, APIs, and real-time services.
Node.js uses a non-blocking, event-driven model to handle thousands of concurrent connections efficiently.It uses asynchronous callbacks and the event loop to avoid blocking the main thread. This makes it fast and memory-efficient, especially for I/O-bound operations.
i) Single Thread + Event Loop
Unlike traditional web servers (e.g., Apache), which spawn multiple threads for each connection, Node.js uses a single main thread.
It handles concurrent connections using an event loop, which listens for events (like HTTP requests, file read/write, etc.) and delegates the heavy work to the background (worker) threads via libuv, a C++ library Node.js uses under the hood.
ii) Event Loop Explained
a) Incoming Request : Client makes a request (e.g., read a file or call an API).b) Event Loop Receives Request : Puts the request in the event queue.
c) Delegation to Worker Thread (if needed) : For I/O tasks like file reading or DB queries, the task is handed to a thread in the libuv thread pool.
d) Continue Processing : While waiting for I/O, Node.js continues handling other events.
e) Callback Triggered : Once the I/O operation finishes, the callback is added to the event loop.
f) Response Sent : Callback is executed, and the result is sent back to the client.
iii) Architecture Components
a) V8 Engine : Compiles and executes JavaScript code.
b) libuv : Handles thread pooling, async I/O, and abstracting OS functionalities.
c) Event Loop : Core component that processes all callbacks and non-blocking tasks.
d) Worker Threads : Handle long-running tasks like file I/O or DNS lookups.
e) NPM : Provides access to third-party packages and modules.Explain the Node.js application architecture?
Node.js follows a modular, layered architecture designed to handle asynchronous I/O operations efficiently. The architecture is event-driven and non-blocking, making it ideal for building fast, scalable network applications like APIs, microservices, real-time apps, and more.
Main Components of Node.js Application Architecture
i) Request-Response ModelNode.js uses a single-threaded event loop to process incoming requests and send back responses. Each incoming request is processed asynchronously.
ii) Core Layers in Node.js Architecture
a) Request Handling Layer
Uses thehttpmodule or frameworks like Express.js to receive HTTP requests.
Handles headers, body parsing, and passes the request to the router.
b) Routing Layer
Determines which controller to invoke based on the URL and HTTP method (GET, POST, etc.).
Typically uses routing middleware likeapp.get(),app.post()in Express.
c) Controller Layer
Handles the main application logic for each endpoint.
Validates input, calls services, handles errors, etc.
d) Service Layer (Business Logic Layer)
Contains the logic for interacting with the data layer, performing computations, etc.
Separates concerns to make code reusable and testable.
e) Data Access Layer
Handles communication with the database (e.g., MongoDB, PostgreSQL).
Uses libraries likemongoose,Sequelize,TypeORM, etc.
f) Response Layer
Prepares the response (e.g., JSON) and sends it back to the client.
Also handles setting HTTP status codes, headers, and error messages.Why Node.js is single-threaded, and how does it handle concurrency and non-blocking I/O operations?
Node.js is single-threaded by design to simplify programming and improve performance for I/O-bound (input/output-heavy) tasks.
1) Reasons for Being Single-Threaded
i) Simplicity: Writing multi-threaded code in JavaScript (especially with shared memory and locking) would be complex and error-prone.ii) JavaScript Origins: JavaScript was originally created for browsers, where it runs in a single thread (the main thread), and Node.js extended this model to the server.
iii) Asynchronous Nature: Node.js doesn’t need multiple threads for concurrency—it achieves it with non-blocking asynchronous I/O and an event-driven architecture.
2) How Node.js Handles Concurrency and Non-blocking I/O
Even though Node.js is single-threaded, it can handle thousands of concurrent connections efficiently using,
i) Event LoopThe event loop is the core of Node.js's concurrency model.
It continuously checks for new events (like HTTP requests, completed file reads, etc.) and executes their associated callbacks.
ii) Non-blocking I/ONode.js uses non-blocking APIs (e.g.,
fs.readFile,http.get) so the main thread doesn’t wait for operations to complete.While I/O tasks run, Node.js continues executing other code.
iii) libuv and Thread PoolNode.js uses libuv, a C/C++ library, to abstract OS-level operations.
For CPU-bound or blocking operations (e.g., file system access, DNS, compression), libuv delegates them to a worker thread pool.
By default, the pool has 4 threads (configurable), allowing these heavy tasks to run in parallel.
3) High-Level Flow of Concurrency
i) A request comes in (e.g., read a file).ii) Node.js passes the task to libuv, which assigns it to a worker thread.
iii) The event loop continues running and handles other incoming requests.
iv) When the file read is complete, the result is passed back to the event loop.
v) The callback for that request is executed, and the response is sent.
What is the package.json file in Node js?
Thepackage.jsonfile is a central configuration file used in Node.js projects. It defines the metadata, dependencies, scripts, and other configurations for your application or module. It’s essentially the manifest file of your Node.js project.
To automatically generate apackage.jsonfile, you can use,npm init # or for a quicker setup npm init -y1) Key Purposes of package.json
i) Manages Project Metadata
Name, version, description, author, license, etc.ii) Lists Dependencies
Third-party libraries your project needs (e.g.,
express,mongoose).Dev dependencies used only during development/testing.
iii) Defines Scripts
Custom commands (e.g.,
npm start,npm test,npm run build).iv) Tracks Versions
Keeps version control of the application and its dependencies.
v) Used by npm and yarn
npm installreads this file to install the right packages.{ "name": "my-app", // Name of the project/module "version": "1.0.0", // Current version of the app "description": "A simple Node.js app", // Brief description of the app "main": "index.js", // Entry point file (default is index.js) "scripts": { // Custom commands (npm run <script-name>) "start": "node index.js", "test": "echo \"No tests yet\" && exit 0" }, "author": "Your Name", // Your name or organization "license": "MIT", // Open-source license type "dependencies": { // Runtime libraries needed for your app "express": "^4.18.2" }, "devDependencies": { // Tools needed only during development/testing "nodemon": "^3.0.1" } }2) Benefits of package.json
i) Automates setup : Others can install all needed packages with
npm install.ii) Makes deployment easier : You can script build, test, and deploy steps.
iii) Supports versioning : Helps manage and lock specific versions of packages.
iv) Enables sharing : Required if you're publishing your package to npm.
Explain REPL in the context of Node.js
REPL stands for: Read – Eval – Print – LoopIn the context of Node.js, REPL is an interactive shell or environment that allows you to write and execute JavaScript code one line at a time directly from the terminal.
It's built into Node.js and is great for testing, debugging, or exploring JavaScript and Node features quickly.
1) How REPL WorksRead: Takes input from the user.
Eval: Evaluates the input.
Print: Prints the result of the evaluation.
Loop: Repeats the process until the user exits.
2) How to Start REPL// To start the Node.js REPL node // You’ll see a prompt like >3) REPL Features
i) JavaScript Execution - Run any valid JavaScript expression or code
ii) Multiline Support - Write multi-line code using loops, functions, etc.
iii) Special Commands -.help,.exit,.load,.save, etc.
iv) Context Access - Access predefined Node.js modules and global objects
v) Underscore (_) - Stores the result of the last evaluated expressionWhat is npm? How is it used in Node.js development?
npm stands for Node Package Manager. It is the default package manager for Node.js and serves two main roles,A command-line tool to install, update, manage, and run Node.js packages.
An online registry (https://www.npmjs.com) containing thousands of open-source JavaScript libraries and tools.
1) How npm Is Used in Node.js Development
i) Installing Packagesnpm install <package-name>Adds the package to the
node_modulesfolder.Updates
package.jsonandpackage-lock.json.
ii) Installing Packages as Dev Dependenciesnpm install --save-dev nodemonUsed only during development (not required in production).
iii) Global Package Installationnpm install -g <package-name>Installs a package globally, making it available from anywhere on your system (e.g.,
npm,nodemon,eslint).
iv) Running ScriptsYou can define and run scripts from package.json
"scripts": { "start": "node app.js", "dev": "nodemon app.js" }npm run dev npm startv) Managing Project Metadata
Thenpm initcommand sets up a new Node.js project and creates apackage.jsonfile with:Project name, Version, Author, License, Dependencies, Scripts
npm init // or for quick setup npm init -yvi) Version Management
npm supports semantic versioning using:
^(caret): Install compatible newer versions~(tilde): Install patch updatesNo symbol: Lock to exact version
"dependencies": { "express": "^4.18.2" }Describe the role of modules in Node.js. How are they created and used?
Modules are reusable pieces of code in Node.js. They help you organize your application into separate files and functions, improving code structure, reusability, and maintainability.
In Node.js, every file is treated as a separate module.
1) Why Use Modules?
i) Encapsulation: Avoid polluting the global scope.ii) Separation of concerns: Divide logic by function (e.g., routes, database, utilities).
iii) Code reuse: Share modules across files or even projects.
2) Types of Modules in Node.jsi) Core Modules (built into Node.js)
e.g.,
fs,http,path,os,url- No installation neededii) Local/User-Defined Modules
Files you create in your own project (e.g.,
math.js)iii) Third-Party Modules:
Installed via npm (e.g.,
express,lodash)Describe the role of the require function in Node.js.
Therequire()function is a built-in Node.js function used to import modules, JSON files, or local files into a Node.js script. It’s a part of the CommonJS module system, which Node.js uses by default.
1) Role ofrequire()in Node.js
Therequire()function allows developers to:Load core Node.js modules (like
fs,http,path)Load third-party modules installed via npm (like
express,lodash)Load custom (local) modules created by the developer
Load JSON files directly
// Loading a Core Module const fs = require('fs'); fs.readFile('file.txt', 'utf8', (err, data) => { console.log(data); });// Loading a Local Module // math.js module.exports = { add: (a, b) => a + b }; // app.js const math = require('./math'); console.log(math.add(2, 3)); // Output: 5What are the differences between require() and import in Node.js?
Both
require()andimportare used to include modules in Node.js, but they come from different module systems and have different syntax, behaviors, and capabilities.// require // math.js module.exports = { add: (a, b) => a + b }; // app.js const math = require('./math'); console.log(math.add(2, 3)); // 5// import // math.mjs export const add = (a, b) => a + b; // app.mjs import { add } from './math.mjs'; console.log(add(2, 3)); // 5When Should You Use Each?
i) Userequire()forOlder projects
Simpler setups
Full compatibility with all npm packages
ii) Use
importforModern, modular codebases
Frontend-backend code sharing
Using top-level
awaitor async module loadingHow do you create a simple HTTP server in Node.js?
Node.js includes a built-inhttpmodule that lets you create a basic HTTP server without installing any external packages.// Load the http module const http = require('http'); // Loads the built-in Node.js HTTP module. // Create the server const server = http.createServer((req, res) => { // Set the response header res.writeHead(200, { 'Content-Type': 'text/plain' }); // Send response res.end('Hello, world!\n'); }); // Define the port const PORT = 3000; // Start the server server.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}/`); });How It Works
i)
require('http')
Loads the built-in Node.js HTTP module.
ii)http.createServer()
Creates the server and provides a callback function that handles incoming requests (req) and sends responses (res).
iii)res.writeHead()
Sets the HTTP status and headers.
iv)res.end()
Ends the response and sends data back to the client.
v)server.listen(PORT)
Binds the server to a specific port (e.g.,3000) so it can receive requests.How do you create a simple HTTP server in Node.js using Express?
i) Install Expressnpm install expressii) Create the server file
Create a file named
server.js(orindex.js) with the following contentconst express = require('express'); const app = express(); const port = 3000; // Define a simple route app.get('/', (req, res) => { res.send('Hello, world!'); }); // Start the server app.listen(port, () => { console.log(`Server is running at http://localhost:${port}`); });iii) Run the server
node server.jsOpen a browser and navigate to
http://localhost:3000.What is the role of the process object in Node.js? Give examples of its usage.
Theprocessobject in Node.js is a global object that provides information and control over the current Node.js process. It’s an instance of theEventEmitterclass and is always available without requiring an import.
Theprocessobject is essential for,Reading input, Handling configuration, Managing the runtime environment
It plays a vital role in writing command-line tools, scripting automation, and managing app behavior dynamically.
i) Key Roles of theprocessObject
a) Accessing command-line argumentsb) Interacting with the environment
c) Controlling the process lifecycle (exit, signals)
d) Handling events (e.g.,
uncaughtException,exit)e) Standard input/output (stdin, stdout, stderr)
ii) Common Examples a) Accessing Command-Line Arguments// Run: node app.js arg1 arg2 console.log(process.argv); // OUTPUT [ 'node', '/path/to/app.js', 'arg1', 'arg2' ]b) Accessing Environment Variables
// Set variable: MY_ENV=production node app.js console.log(process.env.MY_ENV); // "production"c) Exiting the Process
if (!process.env.MY_ENV) { console.error('Missing environment variable'); process.exit(1); // Exit with error code }d) Listening for Exit Events
process.on('exit', (code) => { console.log(`About to exit with code: ${code}`); });e) Standard Output and Error
process.stdout.write('This is standard output\n'); process.stderr.write('This is an error message\n');f) Getting Current Working Directory
console.log(process.cwd());g) Changing Working Directory
process.chdir('/tmp'); console.log('Changed directory to:', process.cwd());What is the role of environment variables in Node.js development and how to manage it?
Environment variables play a critical role in Node.js development by providing a way to configure application behavior without hardcoding values in your source code. They’re especially useful for managing different settings across environments like development, staging, and production.
i) Why Use Environment Variables?a) Security - Keep secrets (API keys, DB passwords) out of code.
b) Flexibility - Configure behavior (ports, debug modes) without editing code.
c) Portability - Make code easier to deploy in different environments.
ii) How to Use Environment Variables in Node.js
a) Accessing an Environment Variableconst port = process.env.PORT || 3000; console.log(`Server will run on port ${port}`);b) Setting Environment Variables
// Linux/macOS PORT=5000 node app.js // Windows (CMD) set PORT=5000 && node app.jsc) Managing with
.envFiles anddotenvFor easier management, especially in development, use the
dotenvpackage.// Install dotenv npm install dotenv // Create a .env file PORT=4000 DB_USER=myuser DB_PASS=secret // Load variables in your app require('dotenv').config(); const port = process.env.PORT || 3000; console.log(`Server is running on port ${port}`);iii) Best Practices
Never commit.envto version control. Use.gitignoreto exclude it.Use environment-specific
.envfiles:.env.development,.env.production, etc.Load them conditionally if needed,
require('dotenv').config({ path: `.env.${process.env.NODE_ENV || 'development'}` });Environment variables help:
a) Keep configs secure and flexible
b) Separate code from configuration
c) Simplify deployment and scaling
How does error handling differ in synchronous and asynchronous code in Node.js?
Error handling in Node.js differs significantly between synchronous and asynchronous code due to the nature of JavaScript's event-driven and non-blocking architecture.i) Synchronous Error Handling
Synchronous code executes sequentially, so you can use
try...catchblocks directlytry { const data = JSON.parse('invalid JSON'); } catch (err) { console.error('Caught an error:', err.message); }If an error is thrown during execution, it's caught immediately.
Simple and predictable.
ii) Asynchronous Error Handling
Asynchronous code doesn’t throw errors in the same call stack, sotry...catchwon't work directly unless you’re usingasync/await.
a) CallbacksWith callbacks, you follow the Node.js error-first callback pattern
const fs = require('fs'); fs.readFile('file.txt', 'utf8', (err, data) => { if (err) { console.error('Error reading file:', err.message); return; } console.log('File data:', data); });First argument to the callback is always an error (if any).
You must manually check and handle
err.b) Promises
You handle errors using
.catch()const fs = require('fs').promises; fs.readFile('file.txt', 'utf8') .then(data => console.log('File data:', data)) .catch(err => console.error('Error reading file:', err.message));c) Async/Await
try...catchworks withasyncfunctionsconst fs = require('fs').promises; async function readFile() { try { const data = await fs.readFile('file.txt', 'utf8'); console.log('File data:', data); } catch (err) { console.error('Error reading file:', err.message); } } readFile();What is an error-first callback in Node.js?
An error-first callback is a convention in Node.js for handling errors in asynchronous functions, especially those that use the callback pattern (common before Promises andasync/await).
i) DefinitionAn error-first callback is a function where:
The first argument is reserved for an error object (if any).
The subsequent arguments are used for successful result data.
ii) Function Signature
function callback(err, result) { if (err) { // handle the error } else { // use the result } }iii) Reading a File with fs
const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error('Error reading file:', err.message); return; } console.log('File content:', data); });If reading fails (e.g. file not found),
errcontains an error anddataisundefined.If successful,
errisnull, anddatacontains the file content.iv) Creating Your Own Error-First Callback Function
function divide(a, b, callback) { if (b === 0) { return callback(new Error("Division by zero")); } const result = a / b; callback(null, result); } // Usage: divide(10, 2, (err, result) => { if (err) { console.error(err.message); } else { console.log('Result:', result); } });What are the global objects of Node.js?
In Node.js, global objects are built-in objects that are accessible from anywhere in your code without importing or requiring them. These differ from browser globals and are specific to the Node.js environment.
i) global
The global namespace object.Similar to
windowin browsers.global.foo = 'bar'; console.log(foo); // barii) process
Provides information and control over the current Node.js process.
Common uses:process.envfor environment variablesprocess.argvfor command-line argumentsprocess.exit(),process.on('exit', ...)
iii) __dirname
The directory name of the current module file.console.log(__dirname); // e.g., /Users/you/projectiv) __filename
The full path of the current module file.console.log(__filename); // e.g., /Users/you/project/index.jsv) require
Function to import modules (CommonJS style).const fs = require('fs');vi) module
Represents the current module.Contains information about the module (e.g.,
module.exports).
vii) exports
A shorthand formodule.exportsexports.sayHello = () => console.log('Hello');viii) Buffer
Used to handle binary data.const buf = Buffer.from('Hello'); console.log(buf); // <Buffer 48 65 6c 6c 6f>ix) setImmediate()
Executes a function after the current event loop cycle.setImmediate(() => console.log('Runs after I/O events'));x)
setTimeout(),clearTimeout(),setInterval(),clearInterval()
Timers, same as in the browser.How would you use a URL module in Node.js?
In Node.js, theurlmodule is used to parse, format, and resolve URLs. It’s built into Node.js, so no installation is required.
i) Importing theurlModule// In CommonJS (default for Node.js) const url = require('url'); // In ES Modules (if using "type": "module" in package.json) import { URL } from 'url';ii) Parsing a URL
Usingurl.parse()(Legacy)const url = require('url'); const parsedUrl = url.parse('https://example.com:8080/path/name?query=123#hash'); console.log(parsedUrl.hostname); // 'example.com' console.log(parsedUrl.port); // '8080' console.log(parsedUrl.query); // 'query=123'Using the modern
URLclassconst { URL } = require('url'); const myUrl = new URL('https://example.com:8080/path/name?query=123#hash'); console.log(myUrl.hostname); // 'example.com' console.log(myUrl.port); // '8080' console.log(myUrl.pathname); // '/path/name' console.log(myUrl.search); // '?query=123' console.log(myUrl.hash); // '#hash'iii) Creating/Modifying a URL
const { URL } = require('url'); const myUrl = new URL('https://example.com'); myUrl.pathname = '/api'; myUrl.searchParams.set('id', '42'); console.log(myUrl.toString()); // 'https://example.com/api?id=42'iv) Working with Query Parameters
console.log(myUrl.searchParams.get('id')); // '42' myUrl.searchParams.append('sort', 'asc'); console.log(myUrl.toString()); // 'https://example.com/api?id=42&sort=asc'