Node.js Interview Questions


What is Node.js?

Node.js is an open-source, server-side platform built on Chrome's V8 JavaScript engine. It allows JavaScript to be used for server-side scripting, enabling the development of scalable, high-performance web applications.

What are the key features of Node.js?

Node.js features asynchronous, event-driven architecture, which makes it lightweight and efficient for handling concurrent connections. It also has a vast ecosystem of npm packages, non-blocking I/O operations, and supports real-time web applications.

How does Node.js handle asynchronous operations?

Node.js uses event-driven, non-blocking I/O operations to handle asynchronous tasks. It employs callbacks, Promises, and async/await syntax to manage asynchronous code execution effectively.

Explain the event loop in Node.js.

The event loop is a crucial component of Node.js responsible for handling asynchronous operations. It continuously listens for events, executes event handlers, and delegates I/O operations to the system, ensuring non-blocking behavior and efficient resource utilization.

What is npm?

npm (Node Package Manager) is the default package manager for Node.js, facilitating the installation, management, and sharing of reusable JavaScript code packages. It hosts over a million packages in its registry, empowering developers to enhance their projects with third-party modules.

How do you create a server in Node.js?

To create a server in Node.js, you can use the built-in 'http' module. You instantiate an HTTP server by calling 'http.createServer()' and passing a request listener function. This function is invoked whenever the server receives an HTTP request.

Explain the difference between Node.js and AJAX.

Node.js and AJAX are both technologies used in web development, but they serve different purposes and operate on different parts of the web stack.

Aspect Node.js AJAX
Type of Technology Server-side JavaScript runtime environment Client-side technique for making asynchronous requests
Primary Purpose Building server-side applications such as web servers, APIs, and real-time web applications Enhancing client-side interaction without page reloading
Architecture Asynchronous, event-driven, non-blocking I/O model Asynchronous, event-driven, typically using XMLHttpRequest or Fetch API
Execution Environment Runs on the server Executes in the client's web browser
Use Cases Backend logic, server-side processing, handling data, serving content Enhancing user experience, fetching data from the server asynchronously
Interaction with Browser Serves content to the browser, does not run in the browser Runs directly in the browser to interact with server endpoints
Example Use Building RESTful APIs, handling file uploads, database operations Form validation, dynamic content loading, updating UI without page refresh
Communication Model Handles server-side logic, responding to client requests Initiates asynchronous requests to the server, processes responses asynchronously
Language JavaScript JavaScript

What is Express.js?

Express.js is a minimalist web application framework for Node.js, providing robust features for building web applications and APIs. It simplifies common tasks such as routing, middleware integration, and request handling, enabling rapid development of server-side applications.

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello, Express!');
});

app.listen(3000, () => {
  console.log('Express server is running on port 3000');
});

How do you handle errors in Node.js?

In Node.js, errors can be handled using try-catch blocks, error-first callbacks, or Promise rejections. Additionally, frameworks like Express.js provide middleware for centralized error handling and custom error responses.

What are streams in Node.js?

Streams are objects used to read or write data sequentially in Node.js, enabling efficient processing of large datasets without loading everything into memory at once. They can be readable, writable, or duplex (both readable and writable), facilitating data manipulation and transmission.

Explain middleware in Express.js.

Middleware functions in Express.js are functions that have access to the request, response, and next middleware function in the application's request-response cycle. They can modify request or response objects, terminate the request-response cycle, or pass control to the next middleware in the stack.

How do you handle file uploads in Node.js?

File uploads in Node.js can be handled using libraries like 'multer' or 'formidable'. These libraries parse incoming form data, extract file uploads, and store them on the server disk or in memory, providing flexibility and security in handling file uploads.

const express = require('express');
const multer  = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();

app.post('/upload', upload.single('file'), (req, res) => {
  res.send('File uploaded successfully');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

What is callback hell? How do you avoid it?

Callback hell refers to the situation where multiple nested callbacks make code hard to read and maintain, leading to poor code quality and difficulty in debugging. It can be avoided by modularizing code, using named functions instead of anonymous callbacks, or adopting Promise-based or async/await syntax for asynchronous operations.

How do you debug Node.js applications?

Node.js applications can be debugged using built-in debugging tools like 'console.log()' statements, Node.js debugger ('node inspect'), or third-party debugging tools like 'ndb' or Visual Studio Code's debugger. Additionally, logging frameworks such as Winston or Bunyan facilitate debugging by providing structured logs and log aggregation capabilities.

const http = require('http');

const server = http.createServer((req, res) => {
  const url = req.url;
  console.log('Request URL:', url);
  res.end('Hello, World!');
});

server.listen(3000, () => {
  console.log('Server is running on port 3000');
});

What is clustering in Node.js?

Clustering in Node.js involves creating multiple instances of the Node.js process to leverage multi-core systems and improve application performance and scalability. It enables load balancing and fault tolerance by distributing incoming requests among worker processes, utilizing all available CPU cores effectively.

What is RESTful API? How do you implement it in Node.js?

A RESTful API is an architectural style for designing networked applications based on the principles of Representational State Transfer (REST). In Node.js, you can implement RESTful APIs using frameworks like Express.js, defining routes for various HTTP methods (GET, POST, PUT, DELETE) to handle resource representations and interactions.

How do you handle authentication in Node.js?

Authentication in Node.js can be implemented using various strategies such as JSON Web Tokens (JWT), session-based authentication, or OAuth. You can use middleware like Passport.js for implementing authentication strategies and protecting routes based on user authentication status and roles.

What is JWT and how does it work?

JWT (JSON Web Token) is a compact, URL-safe means of representing claims to be transferred between two parties. It consists of three parts: header, payload, and signature, which are base64 encoded and concatenated with periods. JWTs are commonly used for authentication and information exchange in web applications.

const jwt = require('jsonwebtoken');

const payload = { username: 'example_user' };
const secretKey = 'secret';

const token = jwt.sign(payload, secretKey);
console.log('JWT:', token);

const decoded = jwt.verify(token, secretKey);
console.log('Decoded:', decoded);

What are Promises in Node.js?

Promises in Node.js represent the eventual completion or failure of an asynchronous operation, allowing asynchronous code to be written in a more readable and manageable way. Promises can be in one of three states: pending, fulfilled, or rejected, and they support chaining and error handling through '.then()' and '.catch()' methods.

Explain the concept of middleware chaining in Express.js.

Middleware chaining in Express.js involves the sequential execution of middleware functions in the order they are defined. Each middleware function can perform specific tasks such as logging, authentication, or data validation before passing control to the next middleware function in the chain using the 'next()' function.

How do you handle sessions in Node.js?

Sessions in Node.js can be managed using libraries like 'express-session', which stores session data on the server and assigns a unique session identifier (sessionID) to each client. Session data can be stored in memory, a database, or a distributed cache, allowing for user authentication and personalized user experiences.

const express = require('express');
const session = require('express-session');
const app = express();

app.use(session({
  secret: 'secret_key',
  resave: false,
  saveUninitialized: true
}));

app.get('/', (req, res) => {
  req.session.views = (req.session.views || 0) + 1;
  res.send(`You visited this page ${req.session.views} times`);
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

What is the role of package.json in Node.js projects?

The 'package.json' file in Node.js projects serves as a manifest for metadata about the project, including dependencies, scripts, and project configuration. It contains information such as project name, version, author, and dependencies required for the project to run, facilitating project management and dependency resolution.

How do you handle CORS in Node.js?

Cross-Origin Resource Sharing (CORS) in Node.js can be handled using middleware like 'cors' in Express.js, which allows or restricts access to resources from different origins based on configured policies. CORS headers are added to HTTP responses to specify allowed origins, methods, and headers for cross-origin requests.

const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors());

app.get('/', (req, res) => {
  res.send('Hello, CORS!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

What is the role of process.argv in Node.js?

'process.argv' in Node.js is an array containing command-line arguments passed to the Node.js process. The first element ('process.argv[0]') is the path to the Node.js executable, and the second element ('process.argv[1]') is the path to the JavaScript file being executed. Additional arguments passed from the command line are stored.

How do you handle environment variables in Node.js?

Environment variables in Node.js can be accessed using the 'process.env' object, which provides access to the environment variables defined in the operating system. Environment variables are commonly used to configure application settings, such as database connection strings or API keys, without hardcoding them into the code.

What is the difference between 'setTimeout()' and 'setInterval()' functions in Node.js?

The setTimeout() and setInterval() functions in Node.js are used for scheduling the execution of code at a later time, but they differ in how they handle repeated execution:

Aspect setTimeout() setInterval()
Purpose Executes a function or code snippet once after a specified delay Executes a function or code snippet repeatedly at specified intervals
Single or Repeated Execution Single execution Repeated execution at specified intervals
Delay/Interval Measurement Delay measured in milliseconds Interval measured in milliseconds
Usage Delaying execution of a function, implementing timeouts Executing tasks at regular intervals

How do you handle file system operations in Node.js?

File system operations in Node.js are handled using the built-in 'fs' module, which provides methods for interacting with the file system. Operations such as reading from or writing to files, creating directories, or modifying file permissions can be performed using 'fs' module functions like 'fs.readFile()', 'fs.writeFile()', 'fs.mkdir()', and 'fs.chmod()'.

const fs = require('fs');

fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('File content:', data);
});

fs.writeFile('example.txt', 'Hello, Node.js!', (err) => {
  if (err) throw err;
  console.log('File saved');
});

What is the role of the '__dirname' and '__filename' variables in Node.js?

The __dirname and __filename variables in Node.js are special globals that provide information about the current working directory and the absolute path of the currently executing script file, respectively.

__dirname:

  • Role: '__dirname' represents the directory name of the current module.
  • Usage: It is commonly used to construct absolute paths for file operations or to resolve paths relative to the current module's directory.

__filename:

  • Role: '__filename' represents the absolute path of the currently executing script file.
  • Usage: It is often used to perform operations specific to the currently executing script, such as reading its content or resolving relative paths.

How do you handle form validation in Node.js?

Form validation in Node.js can be implemented using libraries like 'express-validator', which provides middleware for validating and sanitizing user input from HTML forms. Validation rules can be defined for each form field, and error messages can be generated for invalid input, ensuring data integrity and security.

What is WebSocket in Node.js?

WebSocket is a communication protocol that provides full-duplex, bidirectional communication channels over a single TCP connection. In Node.js, WebSocket functionality can be implemented using libraries like 'ws', allowing for real-time, low-latency communication between clients and servers, ideal for applications requiring instant data exchange.

How do you handle database operations in Node.js?

Database operations in Node.js can be handled using database-specific drivers or ORMs (Object-Relational Mappers) like Sequelize or Mongoose. These libraries provide abstractions for interacting with databases, allowing developers to perform CRUD operations (Create, Read, Update, Delete) on database records using JavaScript.

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydb', { useNewUrlParser: true, useUnifiedTopology: true });

const Schema = mongoose.Schema;
const userSchema = new Schema({
  name: String,
  email: String
});

const User = mongoose.model('User', userSchema);

const user = new User({ name: 'John Doe', email: '[email protected]' });
user.save().then(() => console.log('User saved'));

What is middleware in Node.js and how does it work?

Middleware in Node.js refers to functions that have access to the request and response objects in the application's request-response cycle. Middleware functions can modify request or response objects, terminate the request-response cycle, or pass control to the next middleware function in the stack by calling the 'next()' function.

How do you handle authentication in a RESTful API using Node.js?

Authentication in a RESTful API using Node.js can be implemented using strategies like JSON Web Tokens (JWT), OAuth, or session-based authentication. Middleware like Passport.js can be used to integrate authentication strategies, validate user credentials, and generate access tokens for protected API routes.

What is the role of the 'cluster' module in Node.js?

The 'cluster' module in Node.js allows for the creation of child processes (workers) to utilize multiple CPU cores effectively. It enables load balancing and fault tolerance by distributing incoming requests among worker processes, improving application performance and scalability in multi-core systems.

How do you handle HTTPS in Node.js?

HTTPS in Node.js can be handled using the built-in 'https' module, which provides functionality for creating HTTPS servers and making HTTPS requests. You can create an HTTPS server by passing SSL certificate and key files, enabling secure communication between clients and the server over the HTTPS protocol.

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Hello, HTTPS!');
}).listen(3000);

What is the purpose of the 'util' module in Node.js?

The 'util' module in Node.js provides utility functions that are commonly used for debugging, error handling, and object manipulation. It includes functions for formatting strings, inspecting objects, and converting callback-based functions into Promise-based functions using 'util.promisify()'.

How do you handle cookies in Node.js?

Cookies in Node.js can be handled using middleware like 'cookie-parser', which parses HTTP request cookies and populates 'req.cookies' with cookie data. Cookies can be set, retrieved, and manipulated using the 'Set-Cookie' and 'Cookie' HTTP headers, enabling stateful communication between clients and servers.

What is serverless computing, and how does it relate to Node.js?

Serverless computing is a cloud computing model where cloud providers dynamically manage server resources, allowing developers to focus on writing and deploying code without worrying about server management. Node.js is well-suited for serverless computing due to its lightweight and scalable nature, enabling rapid development and deployment of serverless applications.

// Serverless function example using AWS Lambda
exports.handler = async (event) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello from Lambda!'),
  };
  return response;
};

How do you handle file uploads in Node.js using Express.js?

File uploads in Node.js using Express.js can be handled using middleware like 'multer', which parses multipart form data and stores uploaded files on the server disk or in memory. 'multer' provides configuration options for file size limits, file naming, and destination directories, ensuring secure and efficient file uploads.

What is Redis, and how do you use it with Node.js?

Redis is an open-source, in-memory data structure store used as a database, cache, and message broker. In Node.js, Redis can be used as a caching layer to improve application performance by storing frequently accessed data in memory. Libraries like 'ioredis' provide Node.js clients for interacting with Redis servers, enabling data manipulation and pub/sub messaging.

const redis = require('redis');
const client = redis.createClient();

client.on('connect', () => {
  console.log('Connected to Redis');
});

client.set('key', 'value', redis.print);
client.get('key', redis.print);

How do you implement pagination in Node.js?

Pagination in Node.js involves limiting the number of results returned in a query and providing navigation controls for accessing additional pages of data. Pagination can be implemented using query parameters like 'page' and 'limit', combined with database queries that use 'LIMIT' and 'OFFSET' clauses to fetch subsets of data.

What is GraphQL, and how does it differ from RESTful APIs?

GraphQL is a query language for APIs and a runtime for executing those queries with existing data. It differs from RESTful APIs in that it allows clients to request only the data they need using a single endpoint, reducing over-fetching and under-fetching of data. GraphQL schemas define the data structure, and clients can specify their data requirements using GraphQL queries.

How do you handle cross-site scripting (XSS) attacks in Node.js?

Cross-site scripting (XSS) attacks in Node.js can be prevented by sanitizing user input, escaping special characters, and validating input data before rendering it in HTML pages. Libraries like 'helmet' can be used to set HTTP headers that mitigate XSS attacks, and Content Security Policy (CSP) can be implemented to restrict the sources of executable scripts.

const express = require('express');
const helmet = require('helmet');
const app = express();

app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", 'trusted-scripts.com'],
    styleSrc: ["'self'", 'stylesheets.com'],
    imgSrc: ['data:', 'images.com'],
    sandbox: ['allow-forms', 'allow-scripts'],
    reportUri: '/report-violation',
    objectSrc: ["'none'"],
  }
}));

app.get('/', (req, res) => {
  res.send('Hello, XSS!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

How do you handle WebSocket connections in Node.js?

WebSocket connections in Node.js can be handled using libraries like 'ws' or 'Socket.io'. These libraries provide APIs for creating WebSocket servers, handling client connections, and facilitating real-time bidirectional communication between clients and servers.

What is middleware error handling in Express.js?

Middleware error handling in Express.js involves defining error-handling middleware functions that are executed when errors occur during the request-response cycle. Error-handling middleware can catch errors, log them, and send appropriate error responses to clients, ensuring robustness and reliability in Express.js applications.

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('Client connected');
  
  ws.on('message', (message) => {
    console.log(`Received message: ${message}`);
  });
  
  ws.send('Hello, WebSocket!');
});

How do you implement session management in a stateless environment using Node.js?

Session management in a stateless environment using Node.js can be implemented using techniques like JSON Web Tokens (JWT) or session tokens. JWTs are generated on the server, signed with a secret key, and sent to clients as tokens. Clients include JWTs in subsequent requests, allowing servers to authenticate and authorize users without server-side sessions.

What is the purpose of the 'crypto' module in Node.js?

The 'crypto' module in Node.js provides cryptographic functionality for generating hashes, encrypting and decrypting data, and creating digital signatures. It supports various cryptographic algorithms and provides a secure means of handling sensitive data in Node.js applications.

const jwt = require('jsonwebtoken');

const secretKey = 'secret';

const generateToken = (payload) => {
  return jwt.sign(payload, secretKey, { expiresIn: '1h' });
};

const verifyToken = (token) => {
  return jwt.verify(token, secretKey);
};

const token = generateToken({ userId: 123 });
console.log('JWT:', token);

const decoded = verifyToken(token);
console.log('Decoded:', decoded);

How do you implement rate limiting in Node.js?

Rate limiting in Node.js can be implemented using middleware like 'express-rate-limit', which limits the number of requests a client can make within a specified time window. Rate limiting middleware tracks client requests based on IP addresses or user tokens and responds with appropriate HTTP status codes when rate limits are exceeded, mitigating abuse and ensuring fair resource allocation.

How do you handle unit testing in Node.js?

Unit testing in Node.js can be performed using testing frameworks like Mocha, Jest, or Jasmine. These frameworks provide tools for writing and executing unit tests, defining test suites and assertions, and generating test reports. Additionally, mocking libraries like Sinon.js can be used to simulate dependencies and isolate units of code for testing.

const express = require('express');
const rateLimit = require('express-rate-limit');
const app = express();

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});

app.use(limiter);

app.get('/', (req, res) => {
  res.send

What is the purpose of the 'Buffer' class in Node.js?

The 'Buffer' class in Node.js is used to handle binary data, allowing for the manipulation and storage of raw binary data in memory. It is particularly useful for working with network protocols, file systems, and cryptographic operations where data needs to be represented as bytes.

What is the purpose of the 'Buffer' class in Node.js?

The 'Buffer' class in Node.js is used to handle binary data, allowing for the manipulation and storage of raw binary data in memory. It is particularly useful for working with network protocols, file systems, and cryptographic operations where data needs to be represented as bytes.