← All courses

Interview questionsBackend DevelopmentIntermediate

Top 10 Node.js and backend interview questions

The event loop, streams, Express middleware, authentication, REST design and scaling: the Node.js and backend questions most often asked to freshers and junior developers.

10 min · 10 questions

1How does Node.js handle many requests on a single thread?

Node runs JavaScript on one main thread but does non-blocking I/O. When a request needs the database, a file or another API, Node hands that work to the operating system (or libuv's small thread pool for things like file I/O, DNS and crypto) and keeps serving other requests. When the I/O completes, its callback is queued and the event loop runs it.

So Node is excellent for I/O-heavy workloads (APIs, chat, streaming) where most time is spent waiting. It's poor for CPU-heavy work on the main thread (image processing, big calculations), because that blocks every other request. Fixes: worker threads, a job queue with separate workers, or a service in another language. To use multiple cores, run several processes (cluster, PM2, or multiple containers behind a load balancer).

2Explain the Node.js event loop phases, and process.nextTick vs setImmediate.

The event loop cycles through phases:

  1. timers: setTimeout/setInterval callbacks whose time has come.
  2. pending callbacks: some system-level callbacks.
  3. poll: retrieve new I/O events and run their callbacks; waits here if there's nothing else.
  4. check: setImmediate callbacks.
  5. close callbacks: e.g. socket close events.

Between phases (and after each callback), Node drains the process.nextTick queue first, then the promise microtask queue.

  • process.nextTick(fn) runs before any other queued work, even promises. Overusing it can starve I/O.
  • setImmediate(fn) runs in the check phase, right after I/O callbacks.
  • Inside an I/O callback, setImmediate always runs before setTimeout(fn, 0).

3What is middleware in Express?

Middleware is a function (req, res, next) in the request pipeline. Each one can read or modify req/res, end the request by sending a response, or call next() to pass control on. Order matters: they run in the order registered.

js
app.use(express.json());                 // parse body
app.use(requestLogger);                  // log every request
app.use("/api", rateLimit({ max: 100 })); // protect the API
app.get("/api/me", requireAuth, (req, res) => res.json(req.user));
app.use(errorHandler);                   // (err, req, res, next): last

Types: application-level, router-level, built-in (express.json, express.static), third-party (cors, helmet) and error-handling middleware, which has four arguments and receives errors passed with next(err).

4What are streams in Node.js and when would you use them?

Streams process data piece by piece instead of loading it all into memory. Types: Readable, Writable, Duplex (both, like a socket) and Transform (modify data as it passes, like gzip).

js
import { pipeline } from "node:stream/promises";
import { createReadStream, createWriteStream } from "node:fs";
import { createGzip } from "node:zlib";

await pipeline(createReadStream("export.csv"), createGzip(), createWriteStream("export.csv.gz"));

Use them for large files, CSV exports, video, proxying uploads, or reading big database results. They keep memory flat and start sending data immediately. pipeline handles backpressure (pausing a fast producer when the consumer is slow) and cleans up on errors.

5How do you handle errors in Node.js and Express?

  • Synchronous code: try/catch.
  • Promises and async/await: try/catch around await, or .catch(). Unhandled rejections crash modern Node processes.
  • Express: forward errors with next(err) to one central error-handling middleware that logs them and returns a clean JSON response with the right status code. In Express 4, async route handlers must catch and forward errors themselves (or use a wrapper); Express 5 forwards rejected promises automatically.
  • Distinguish operational errors (invalid input → 400, not found → 404, a downstream timeout → 503) from programmer errors (bugs → 500, log with a stack trace).
  • Never leak stack traces or SQL errors to clients.
  • Process level: log uncaughtException/unhandledRejection, then exit and let the process manager restart a clean process.

6Explain JWT authentication. What are its pros and cons?

A JWT has three base64url parts: header (algorithm), payload (claims such as user id, role, expiry) and signature. After login the server signs a token; the client sends it on each request (Authorization: Bearer … or a cookie); the server verifies the signature and expiry without a database lookup.

Pros: stateless, works across services and domains, scales easily.

Cons: hard to revoke before expiry; the payload is readable by anyone (encoded, not encrypted); a stolen token works until it expires.

Good practice: short-lived access tokens (5–15 min) plus a rotating refresh token stored in an HttpOnly, Secure, SameSite cookie; check a token version or deny list for logout-everywhere; use strong secrets or asymmetric keys; always validate exp, iss and aud.

7What makes an API RESTful? Design endpoints for a job portal.

REST principles: resources identified by URLs, standard HTTP methods for actions, stateless requests (each request carries its own auth), meaningful status codes, cacheable responses and a uniform interface.

text
GET    /jobs?city=pune&type=internship&page=1   list and filter
POST   /jobs                                    company creates a job
GET    /jobs/{id}                               job details
PATCH  /jobs/{id}                               edit some fields
DELETE /jobs/{id}                               close/delete
POST   /jobs/{id}/applications                  student applies (201, or 409 if already applied)
GET    /jobs/{id}/applications?status=shortlisted  company reviews
PATCH  /applications/{id}                       change status

Mention validation (400/422), authorisation checks (403), pagination, consistent error bodies and versioning.

8What's the difference between SQL and NoSQL databases? Which would you pick?

  • SQL (PostgreSQL, MySQL): fixed schema, tables with relations, joins, ACID transactions. Great when data is relational and consistency matters (users, payments, applications).
  • NoSQL covers several types: document (MongoDB), key-value (Redis), wide-column (Cassandra), graph (Neo4j). Flexible schemas and easy horizontal scaling, usually with weaker cross-record consistency and fewer joins.

My answer would be: pick based on access patterns. For a job portal with users, companies, jobs and applications linked together, a relational database fits naturally. Add Redis for caching and rate limits, and a search engine if full-text search grows. Use MongoDB when records vary in shape and are read as whole documents.

9How would you scale a Node.js application?

  1. Measure first: find the bottleneck (CPU, DB, external API) with metrics and profiling.
  2. Make it stateless: sessions in Redis or tokens, files in object storage, so any instance can serve any request.
  3. Horizontal scaling: multiple processes per machine (cluster/PM2) and multiple machines/containers behind a load balancer.
  4. Database: indexes, fixing N+1 queries, connection pooling, read replicas, caching hot data in Redis.
  5. Offload work: queues and workers for emails, reports, image and AI processing.
  6. Edge: CDN for static assets and cacheable responses, compression.
  7. Resilience: timeouts, retries with backoff, circuit breakers for downstream services, rate limiting.

10How do you secure a Node.js API?

  • Validate and sanitise all input (zod/Joi); limit body size.
  • Use parameterised queries to prevent SQL/NoSQL injection.
  • Hash passwords with bcrypt or argon2; never log secrets.
  • Authenticate every protected route and authorise ownership of every resource accessed (prevents IDOR).
  • Set security headers with helmet; enable HTTPS; restrict CORS to known origins.
  • Rate-limit login, OTP and expensive endpoints.
  • Store secrets in environment variables or a secret manager, not in code.
  • Keep dependencies updated (npm audit, Dependabot) and pin versions with a lockfile.
  • Return generic error messages; log details server-side.
  • For uploads: check type and size, rename files, store outside the web root or in object storage, and scan if needed.

Keep going