Node.js is the dominant JavaScript runtime for backend development at Indian product companies and startups. Swiggy, Zomato, Razorpay, PhonePe, and CRED all run significant Node.js workloads. Interviews test the event loop, async patterns, Express architecture, REST API design, and performance. This guide covers Node.js interview questions for Indian companies in 2026.
The Node.js event loop and non-blocking I/O
The event loop is the most-asked Node.js interview topic:
1. How Node.js works: Node.js is single-threaded but handles concurrency through the event loop and libuv's thread pool. When a non-blocking I/O operation (network request, file read) is initiated, Node.js delegates it to the OS or libuv's thread pool, then continues executing other JavaScript. When the I/O completes, the callback is queued in the event loop and executed when the call stack is empty.
2. Event loop phases (in order): - timers: executes setTimeout and setInterval callbacks whose delay has expired. - pending callbacks: I/O callbacks deferred to the next iteration. - idle, prepare: internal use only. - poll: retrieves new I/O events; executes I/O callbacks. If no timers are scheduled and no callbacks pending, waits here. - check: executes setImmediate callbacks. - close callbacks: e.g., socket.on('close'). Between each phase, Node.js processes the nextTick queue (process.nextTick) and Promise microtask queue before moving to the next phase.
3. process.nextTick vs setImmediate vs setTimeout: process.nextTick: runs before the next event loop phase begins (highest priority among async callbacks). setImmediate: runs in the check phase (after poll). setTimeout(fn, 0): runs in the timers phase; minimum delay ~1ms, so setImmediate can fire before it in certain contexts.
4. Blocking the event loop: CPU-intensive synchronous code (large loops, JSON.stringify on a 10MB object, synchronous file reads) blocks the event loop and prevents it from handling other requests. Mitigation: use worker threads (worker_threads module) for CPU-intensive work; use streaming for large data; avoid fs.readFileSync in server code.
Express.js, middleware, and REST API design
Express is the most common Node.js web framework in India:
1. Express middleware: Middleware functions have access to req, res, and next. Called in order they are registered. Types: application-level (app.use), router-level (router.use), error-handling (four-parameter: (err, req, res, next)), built-in (express.json, express.static), third-party (morgan for logging, cors, helmet for security headers). Order matters: body parsing middleware must be registered before route handlers that read req.body; error-handling middleware must be registered last.
2. Error handling in Express: Synchronous errors in route handlers are caught by Express automatically and forwarded to error middleware. Asynchronous errors must be explicitly caught and passed to next(err): router.get('/user/:id', async (req, res, next) => { try { const user = await getUser(req.params.id); res.json(user); } catch (err) { next(err); } }). Global error handler: app.use((err, req, res, next) => { res.status(err.status || 500).json({ error: err.message }); }).
3. REST API design best practices: Resource naming: plural nouns for collections (/users, /orders), nested for relationships (/users/:id/orders). HTTP methods: GET (read), POST (create), PUT (full update), PATCH (partial update), DELETE (remove). Status codes: 200 (OK), 201 (Created), 204 (No Content), 400 (Bad Request), 401 (Unauthorized), 403 (Forbidden), 404 (Not Found), 409 (Conflict), 422 (Unprocessable Entity), 500 (Internal Server Error). Versioning: /api/v1/users. Pagination: limit/offset or cursor-based for large collections.
4. Authentication in Node.js: JWT (JSON Web Token): stateless; server signs a token on login; client sends it in Authorization: Bearer <token> header; server verifies the signature on each request. No database lookup needed for verification (unlike session tokens). Refresh tokens: short-lived access token (15m) + long-lived refresh token (7d); client uses refresh token to get a new access token. Libraries: jsonwebtoken for signing/verifying, bcrypt for password hashing.
Node.js performance, clustering, and microservices
Advanced Node.js topics for senior roles:
1. Clustering: Node.js is single-threaded, so it uses only one CPU core by default. The cluster module forks multiple worker processes (one per CPU core), each running the same server code. The master process load-balances incoming connections across workers. const cluster = require('cluster'); const os = require('os'); if (cluster.isPrimary) { os.cpus().forEach(() => cluster.fork()); } else { app.listen(3000); }. PM2: production process manager that handles clustering, restarts on crash, and log management.
2. Streams: Streams process data in chunks instead of loading everything into memory. Types: Readable (fs.createReadStream), Writable (fs.createWriteStream), Duplex (both), Transform (modify data as it passes through, e.g., zlib.createGzip). Pipe: readable.pipe(transform).pipe(writable). Use for: large file serving, CSV/JSON processing, HTTP response streaming. Prevents out-of-memory errors on large payloads.
3. Microservices with Node.js: Node.js is well-suited for microservices due to its fast startup, low memory footprint, and async I/O. Communication patterns: synchronous REST/HTTP (axios, node-fetch), asynchronous messaging (RabbitMQ, Kafka, AWS SQS). Service discovery: each service registers with a registry (Consul, Kubernetes DNS). API gateway: single entry point that routes to downstream services, handles auth, rate limiting, and SSL termination. Node.js microservices at Indian companies: Swiggy (order service, delivery tracking), Razorpay (payment gateway, webhook delivery), Zomato (restaurant search, order management).
4. Memory management and debugging: Node.js uses V8's garbage collector (generational GC: young generation for short-lived objects, old generation for long-lived). Memory leaks: global variables, event listener accumulation (use emitter.removeListener), closures retaining large objects. Debugging: node --inspect + Chrome DevTools, clinic.js (flame graphs, heap profiling), 0x (flamegraph profiler). Heap snapshots via v8.writeHeapSnapshot() to diagnose memory leaks in production.
Frequently asked questions
Explore more