Tutorials Logic, IN info@tutorialslogic.com
Node.js

Top 50 Node.js Interview Questions

Curated questions covering event loop, streams, modules, Express.js, async/await, npm, REST APIs, clustering, and Node.js architecture.

01

What is Node.js and what makes it different from browser JavaScript?

Node.js is a JavaScript runtime built on Chrome V8 engine that runs JavaScript on the server. Differences: Node has no DOM/window/document; it has access to the file system, network, and OS via built-in modules (fs, http, path, os); it uses CommonJS/ESM modules; it is single-threaded with non-blocking I/O.

02

What is the Node.js event loop?

The event loop allows Node.js to perform non-blocking I/O despite being single-threaded. It processes callbacks in phases: timers (setTimeout/setInterval), pending callbacks, idle/prepare, poll (I/O), check (setImmediate), close callbacks. Each phase has a FIFO queue of callbacks.

Example
console.log("1");
setTimeout(() => console.log("2"), 0);  // timers phase
setImmediate(() => console.log("3"));    // check phase
Promise.resolve().then(() => console.log("4")); // microtask
console.log("5");
// Output: 1, 5, 4, 2, 3
03

What is the difference between process.nextTick() and setImmediate()?

  • process.nextTick() - fires after the current operation completes, before the event loop continues to the next phase. Highest priority async callback.
  • setImmediate() - fires in the check phase of the event loop, after I/O callbacks.
  • Use process.nextTick() for callbacks that must run before any I/O; use setImmediate() for callbacks that should run after I/O.
Example
setImmediate(() => console.log("setImmediate"));
process.nextTick(() => console.log("nextTick"));
// Output: nextTick, setImmediate
04

What is the difference between CommonJS and ES Modules in Node.js?

  • CommonJS (require/module.exports) - synchronous; default in Node.js; .js extension; loaded at runtime.
  • ES Modules (import/export) - asynchronous; use .mjs extension or "type":"module" in package.json; static analysis; tree-shakeable.
  • Node.js 12+ supports both. ESM is the modern standard.
Example
// CommonJS
const fs = require("fs");
module.exports = { readFile };

// ESM
import fs from "fs";
export { readFile };
05

What is the difference between synchronous and asynchronous file operations in Node.js?

Synchronous operations (fs.readFileSync) block the event loop until complete. Asynchronous operations (fs.readFile, fs.promises.readFile) are non-blocking. Always use async operations in production to avoid blocking other requests.

Example
// Async (preferred)
const data = await fs.promises.readFile("file.txt", "utf8");

// Sync (blocks event loop - avoid in servers)
const data = fs.readFileSync("file.txt", "utf8");
06

What are Node.js streams and what are the four types?

Streams process data in chunks rather than loading everything into memory. Four types:

  • Readable - source of data (fs.createReadStream, http.IncomingMessage).
  • Writable - destination for data (fs.createWriteStream, http.ServerResponse).
  • Duplex - both readable and writable (net.Socket).
  • Transform - duplex stream that modifies data (zlib.createGzip).
Example
const readable = fs.createReadStream("large.csv");
const writable = fs.createWriteStream("output.csv");
readable.pipe(writable); // memory-efficient piping
07

What is the difference between pipe() and pipeline() in Node.js streams?

  • pipe() - connects streams but does not handle errors automatically. If a stream errors, the destination is not closed, causing memory leaks.
  • pipeline() - properly handles errors and cleanup across all streams. Always prefer pipeline() in production.
Example
const { pipeline } = require("stream/promises");

await pipeline(
  fs.createReadStream("input.txt"),
  zlib.createGzip(),
  fs.createWriteStream("output.gz")
); // auto-cleans up on error
08

What is the Node.js cluster module?

The cluster module allows Node.js to create child processes (workers) that share the same server port, utilizing multiple CPU cores. The master process manages workers and distributes incoming connections.

Example
const cluster = require("cluster");
const os = require("os");

if (cluster.isPrimary) {
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }
} else {
  require("./server"); // each worker runs the server
}
09

What is the difference between child_process.spawn(), exec(), and fork()?

  • spawn() - launches a new process with a command. Streams stdout/stderr. Best for large output.
  • exec() - runs a command in a shell. Buffers output. Best for small output with shell features.
  • fork() - special spawn for Node.js scripts. Creates a new Node.js process with IPC channel for message passing.
Example
const { spawn, exec, fork } = require("child_process");
spawn("ls", ["-la"]);          // streams output
exec("ls -la", (err, stdout) => console.log(stdout)); // buffered
fork("./worker.js");           // Node.js child with IPC
10

What is the Node.js worker_threads module?

worker_threads enables true multi-threading in Node.js for CPU-intensive tasks. Unlike cluster (multiple processes), workers share memory via SharedArrayBuffer and communicate via message passing. Use for heavy computation to avoid blocking the event loop.

Example
const { Worker, isMainThread, parentPort } = require("worker_threads");

if (isMainThread) {
  const worker = new Worker(__filename);
  worker.on("message", result => console.log(result));
  worker.postMessage({ data: [1,2,3] });
} else {
  parentPort.on("message", ({ data }) => {
    parentPort.postMessage(data.reduce((a,b) => a+b, 0));
  });
}
11

What is Express.js and what are its core concepts?

Express.js is a minimal, unopinionated web framework for Node.js. Core concepts: routing (app.get/post/put/delete), middleware (functions that process req/res), request/response objects, error handling middleware, and template engines.

Example
const express = require("express");
const app = express();

app.use(express.json()); // middleware

app.get("/users", async (req, res) => {
  const users = await User.findAll();
  res.json(users);
});

app.listen(3000);
12

What is Express middleware and how does it work?

Middleware functions have access to req, res, and next. They execute in order and can modify req/res, end the request, or call next() to pass control. Types: application-level, router-level, error-handling (4 params), built-in, and third-party.

Example
// Logger middleware
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next(); // pass to next middleware
});

// Error handling middleware (4 params)
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message });
});
13

What is the difference between app.use() and app.get() in Express?

  • app.use(path, middleware) - mounts middleware for ALL HTTP methods. Path is optional (defaults to "/"). Matches any route starting with the path.
  • app.get(path, handler) - handles only GET requests for an exact path match.
  • app.use() is for middleware; app.get/post/put/delete() are for route handlers.
14

What is the Node.js Buffer class?

Buffer represents fixed-length raw binary data. Used for working with binary data from files, network streams, and cryptography. Buffers are allocated outside the V8 heap.

Example
const buf = Buffer.from("Hello", "utf8");
console.log(buf);           // <Buffer 48 65 6c 6c 6f>
console.log(buf.toString()); // "Hello"

const buf2 = Buffer.alloc(10); // zero-filled 10-byte buffer
15

What is the difference between Buffer.alloc() and Buffer.allocUnsafe()?

  • Buffer.alloc(size) - allocates a zero-filled buffer. Safe but slower.
  • Buffer.allocUnsafe(size) - allocates without zeroing memory. Faster but may contain old data. Only use when you will immediately fill the buffer.
16

What is the Node.js EventEmitter?

EventEmitter is the foundation of Node.js event-driven architecture. Objects emit named events and listeners respond. Most Node.js core modules (streams, http, fs) extend EventEmitter.

Example
const { EventEmitter } = require("events");

class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();

emitter.on("data", (chunk) => console.log("Received:", chunk));
emitter.emit("data", "hello"); // "Received: hello"
17

What is the difference between on() and once() in EventEmitter?

  • on(event, listener) - registers a persistent listener that fires every time the event is emitted.
  • once(event, listener) - registers a listener that fires only the first time the event is emitted, then automatically removes itself.
18

What is npm and what is the difference between dependencies and devDependencies?

  • dependencies - packages required at runtime in production (express, mongoose, lodash).
  • devDependencies - packages only needed during development (jest, eslint, typescript, nodemon).
  • Install with: npm install pkg (dependency) or npm install pkg --save-dev (devDependency).
19

What is the difference between npm install and npm ci?

  • npm install - installs dependencies, updates package-lock.json if needed. Used during development.
  • npm ci - installs exact versions from package-lock.json, deletes node_modules first. Faster and deterministic. Use in CI/CD pipelines.
20

What is the purpose of package-lock.json?

package-lock.json locks the exact version of every installed package and its dependencies, ensuring reproducible installs across environments. It should be committed to version control. npm ci uses it for deterministic installs.

21

What is the difference between __dirname and process.cwd()?

  • __dirname - the absolute path of the directory containing the current module file. Does not change regardless of where Node.js was started.
  • process.cwd() - the current working directory from which Node.js was launched. Can change with process.chdir().
Example
// In /home/user/app/src/server.js
console.log(__dirname);    // /home/user/app/src
console.log(process.cwd()); // /home/user/app (where node was run)
22

What is the Node.js path module and why use it?

The path module provides utilities for working with file and directory paths in a cross-platform way. Always use path.join() instead of string concatenation to handle OS differences (/ vs \).

Example
const path = require("path");

path.join(__dirname, "public", "index.html"); // cross-platform
path.resolve("./config.json");  // absolute path
path.extname("file.txt");        // ".txt"
path.basename("/foo/bar.js");    // "bar.js"
23

What is the difference between http and https modules in Node.js?

http creates an unencrypted HTTP server. https creates a TLS/SSL encrypted server requiring a certificate and private key. In production, use a reverse proxy (Nginx) for HTTPS termination rather than handling it in Node.js directly.

Example
const https = require("https");
const fs = require("fs");

const server = https.createServer({
  key: fs.readFileSync("key.pem"),
  cert: fs.readFileSync("cert.pem")
}, app);
server.listen(443);
24

What is the Node.js crypto module?

The crypto module provides cryptographic functionality: hashing (SHA-256, MD5), HMAC, encryption/decryption (AES), key generation, and random bytes. Use bcrypt or argon2 for password hashing (not crypto.createHash).

Example
const crypto = require("crypto");

// Hash
const hash = crypto.createHash("sha256").update("data").digest("hex");

// Random token
const token = crypto.randomBytes(32).toString("hex");

// HMAC
const hmac = crypto.createHmac("sha256", "secret").update("data").digest("hex");
25

What is the difference between JWT and session-based authentication?

  • Session-based - server stores session data; client holds a session ID cookie. Stateful. Easy to invalidate. Requires shared session store for horizontal scaling.
  • JWT - server issues a signed token; client stores it (localStorage/cookie). Stateless. No server storage needed. Hard to invalidate before expiry. Scales easily.
Example
const jwt = require("jsonwebtoken");
const token = jwt.sign({ userId: 1 }, process.env.JWT_SECRET, { expiresIn: "1h" });
const decoded = jwt.verify(token, process.env.JWT_SECRET);
26

What is the difference between SQL and NoSQL databases in a Node.js context?

  • SQL (PostgreSQL, MySQL) - structured schema, ACID transactions, complex queries with JOINs. Use Sequelize or Prisma ORM.
  • NoSQL (MongoDB) - flexible schema, horizontal scaling, document-based. Use Mongoose ODM.
  • Choose SQL for relational data with complex queries; NoSQL for flexible, high-volume, document-oriented data.
27

What is Mongoose and what does it provide over the MongoDB driver?

Mongoose is an ODM (Object Document Mapper) for MongoDB. It adds: schema definition with validation, middleware (pre/post hooks), virtuals, population (joins), query building, and TypeScript support. The native driver is lower-level with no schema enforcement.

Example
const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true }
});

userSchema.pre("save", async function() {
  this.password = await bcrypt.hash(this.password, 10);
});
28

What is the difference between REST and GraphQL APIs?

  • REST - multiple endpoints, each returning fixed data shapes. Can over-fetch or under-fetch data.
  • GraphQL - single endpoint, client specifies exactly what data it needs. No over/under-fetching. Strongly typed schema. Better for complex, nested data.
29

What is rate limiting and how do you implement it in Express?

Rate limiting restricts the number of requests a client can make in a time window, protecting against brute force and DDoS attacks. Use express-rate-limit middleware.

Example
const rateLimit = require("express-rate-limit");

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // max 100 requests per window
  message: "Too many requests"
});

app.use("/api/", limiter);
30

What is the difference between process.env and dotenv?

process.env provides access to environment variables set in the OS or shell. dotenv loads variables from a .env file into process.env during development. Never commit .env files. In production, set environment variables directly in the hosting platform.

Example
require("dotenv").config();

const dbUrl = process.env.DATABASE_URL;
const port = process.env.PORT || 3000;
31

What is CORS and how do you handle it in Express?

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that blocks requests from different origins. Configure it in Express using the cors middleware.

Example
const cors = require("cors");

app.use(cors({
  origin: ["https://myapp.com", "https://staging.myapp.com"],
  methods: ["GET", "POST", "PUT", "DELETE"],
  credentials: true
}));
32

What is the difference between horizontal and vertical scaling in Node.js?

  • Vertical scaling - adding more CPU/RAM to a single server. Limited by hardware ceiling.
  • Horizontal scaling - adding more server instances behind a load balancer. Node.js cluster module or PM2 enables multi-core usage on one machine. Docker/Kubernetes for multi-machine scaling.
33

What is PM2 and why is it used?

PM2 is a production process manager for Node.js. Features: automatic restart on crash, cluster mode (multi-core), log management, monitoring, zero-downtime reloads, and startup scripts. Essential for production deployments.

Example
pm2 start app.js --name "api" -i max  # cluster mode, all CPUs
pm2 restart api
pm2 logs api
pm2 monit
34

What is the difference between try/catch and .catch() for async error handling?

  • try/catch with async/await - synchronous-looking error handling. Catches both sync and async errors.
  • Promise .catch() - handles rejected Promises in chain style.
  • Always handle errors in Express with next(err) to pass to error middleware.
Example
// Express async error handling
app.get("/users", async (req, res, next) => {
  try {
    const users = await User.find();
    res.json(users);
  } catch (err) {
    next(err); // passes to error middleware
  }
});
35

What is the Node.js os module?

The os module provides operating system information: CPU count (os.cpus().length), total/free memory, hostname, platform, network interfaces, and temp directory. Useful for cluster setup and system monitoring.

Example
const os = require("os");
console.log(os.cpus().length);  // number of CPU cores
console.log(os.totalmem());     // total RAM in bytes
console.log(os.platform());     // "linux", "win32", "darwin"
36

What is the difference between readFile and createReadStream?

  • fs.readFile() - reads the entire file into memory at once. Simple but memory-intensive for large files.
  • fs.createReadStream() - reads the file in chunks. Memory-efficient for large files. Use with pipe() for processing.
  • Use createReadStream for files > a few MB.
37

What is the Node.js net module?

The net module provides TCP/IPC networking. Used to create raw TCP servers and clients. The http module is built on top of net. Useful for custom protocols, game servers, and inter-process communication.

Example
const net = require("net");

const server = net.createServer((socket) => {
  socket.write("Hello\n");
  socket.on("data", data => console.log(data.toString()));
});
server.listen(8080);
38

What is the difference between synchronous and asynchronous middleware in Express?

Synchronous middleware calls next() directly. Asynchronous middleware uses async/await or Promises. Unhandled Promise rejections in async middleware will not be caught by Express error handlers unless you explicitly call next(err) or use an async wrapper.

Example
// Async middleware - must catch errors
app.use(async (req, res, next) => {
  try {
    req.user = await getUser(req.headers.authorization);
    next();
  } catch (err) {
    next(err);
  }
});
39

What is the difference between app.listen() and http.createServer()?

  • app.listen(port) - shorthand that internally calls http.createServer(app).listen(port). Sufficient for most cases.
  • http.createServer(app) - gives you direct access to the server instance, needed for WebSockets (socket.io), HTTPS, or HTTP/2.
Example
const server = http.createServer(app);
const io = require("socket.io")(server);
server.listen(3000); // needed for WebSocket support
40

What is the Node.js util module?

The util module provides utility functions: util.promisify() (converts callback-based functions to Promises), util.inspect() (deep object inspection), util.format() (string formatting), and util.inherits() (prototype inheritance).

Example
const util = require("util");
const readFile = util.promisify(fs.readFile);

// Now use with async/await
const data = await readFile("file.txt", "utf8");
41

What is the difference between a monolith and microservices architecture in Node.js?

  • Monolith - single deployable unit. Simpler to develop and debug. Harder to scale individual parts.
  • Microservices - independent services communicating via HTTP/gRPC/message queues. Independently deployable and scalable. More operational complexity.
  • Node.js is well-suited for microservices due to its lightweight nature and fast startup time.
42

What is the difference between WebSockets and HTTP in Node.js?

  • HTTP - request/response model. Client initiates every communication. Stateless.
  • WebSockets - full-duplex persistent connection. Both client and server can send messages at any time. Use socket.io or the ws library.
Example
const { Server } = require("socket.io");
const io = new Server(server);

io.on("connection", (socket) => {
  socket.on("message", data => io.emit("message", data));
});
43

What is the difference between bcrypt and crypto for password hashing?

  • crypto.createHash() - fast hashing (SHA-256, MD5). NOT suitable for passwords - too fast, vulnerable to brute force.
  • bcrypt/argon2 - slow by design with configurable cost factor. Includes salt automatically. Purpose-built for password hashing.
Example
const bcrypt = require("bcrypt");

// Hash
const hash = await bcrypt.hash(password, 12); // cost factor 12

// Verify
const match = await bcrypt.compare(password, hash);
44

What is the difference between Prisma and Sequelize?

  • Sequelize - mature ORM for SQL databases. Model-based, JavaScript-first. Verbose but flexible.
  • Prisma - modern ORM with schema-first approach. Auto-generates TypeScript types. Better DX, type safety, and migrations. Recommended for new projects.
Example
// Prisma
const users = await prisma.user.findMany({
  where: { active: true },
  include: { posts: true }
});
45

What is the difference between caching strategies in Node.js?

  • In-memory cache (Map/node-cache) - fastest, lost on restart, single instance only.
  • Redis - distributed cache, persists across restarts, shared across multiple Node.js instances. Best for production.
  • CDN caching - for static assets and API responses at the edge.
Example
const redis = require("ioredis");
const client = new redis();

await client.set("user:1", JSON.stringify(user), "EX", 3600); // 1hr TTL
const cached = await client.get("user:1");
46

What is the difference between graceful shutdown and abrupt termination?

Graceful shutdown allows in-flight requests to complete before the process exits. Abrupt termination (SIGKILL) immediately kills the process, potentially corrupting data or dropping requests.

Example
process.on("SIGTERM", async () => {
  console.log("Shutting down gracefully...");
  server.close(async () => {
    await db.disconnect();
    process.exit(0);
  });
});
47

What is the difference between require() caching and module re-evaluation?

Node.js caches modules after the first require() call. Subsequent require() calls return the cached exports without re-executing the module. This means modules are singletons. Delete require.cache[key] to force re-evaluation (rarely needed).

Example
// Both return the same instance
const a = require("./config");
const b = require("./config");
console.log(a === b); // true - same cached object
48

What is the difference between Node.js 18 fetch and the node-fetch package?

Node.js 18+ includes a built-in fetch API (same as browser fetch), eliminating the need for node-fetch or axios for simple HTTP requests. For advanced features (interceptors, automatic JSON, retries), axios or got are still useful.

Example
// Node.js 18+ built-in fetch
const res = await fetch("https://api.example.com/users");
const users = await res.json();
49

What is the difference between synchronous and asynchronous logging in Node.js?

  • Synchronous logging (console.log) - blocks the event loop. Acceptable in development, problematic in production under load.
  • Asynchronous logging (Winston, Pino) - writes logs in a non-blocking way. Pino is the fastest Node.js logger. Use structured JSON logging in production.
Example
const pino = require("pino");
const logger = pino({ level: "info" });

logger.info({ userId: 1, action: "login" }, "User logged in");
50

What is the difference between Node.js LTS and Current releases?

  • LTS (Long Term Support) - even-numbered versions (18, 20, 22). Supported for 30 months. Recommended for production.
  • Current - latest features, odd-numbered versions. Shorter support window. Use for testing new features.
  • Always use LTS in production for stability and security patches.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.