Skip to content

Senior Backend Engineer (Node.js) Interview Questions & Answers

40 questions for Senior Backend Engineer (Node.js) interviews — 20 medium, 20 hard.

About the Senior Backend Engineer (Node.js) role

Owns the design and reliability of backend services at scale. Leads architecture decisions on databases, caching, queues and service boundaries, improves performance and observability, mentors developers and reviews critical code. Handles incidents, capacity planning for traffic spikes and security reviews, and works with product and engineering managers on technical roadmaps.

System design Performance tuning Microservices Observability Mentoring
Solved for this roleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is the difference between process.nextTick and setImmediate?

Save to ▾
Show answer
process.nextTick queues a callback to run immediately after the current operation, before the event loop continues to any phase, even before promise microtasks. setImmediate queues a callback for the check phase of the next loop iteration. Overusing nextTick recursively can starve I/O because the loop never moves on, so setImmediate is safer for deferring heavy work.
02

What is connection pooling and why is it important in Node.js?

Save to ▾
Show answer
Opening a database connection is slow, so a pool keeps a set of open connections that requests borrow and return. pg Pool, mysql2 and the MongoDB driver all pool by default. Size the pool based on database limits and instance count; too small causes waiting, too large overloads the database. In serverless functions, reuse the client across invocations or use a proxy like RDS Proxy.
03

What is the N+1 query problem and how do you fix it?

Save to ▾
Show answer
N+1 happens when you run one query to fetch a list and then one extra query per item, for example loading 100 posts and then each author separately, causing 101 queries. Fix it with joins or eager loading in SQL ORMs like include in Prisma or Sequelize, populate or $lookup in MongoDB, batching with an IN query, or DataLoader in GraphQL.
04

Memory usage of a Node.js service grows steadily until the pod restarts. How would you find the leak?

Save to ▾
Show answer
First confirm with metrics that heap used keeps rising under steady traffic. Take heap snapshots with --inspect and Chrome DevTools or heapdump at intervals and compare them to find objects whose count keeps growing. Common causes are global caches without limits, event listeners added per request, closures holding large objects and unclosed timers. Fix, then load test with autocannon to verify heap stabilises.
05

Your app gets 'too many connections' errors from PostgreSQL after scaling to 20 pods. What would you do?

Save to ▾
Show answer
Each pod opens its own pool, so 20 pods with max 20 connections need 400, beyond the database limit. Reduce the per-pod pool size, put PgBouncer or RDS Proxy in front of the database for transaction pooling, and make sure connections are released, for example client.release() in finally blocks. Also check for long-running idle transactions holding connections.
06

How do worker_threads differ from the cluster module?

Save to ▾
Show answer
worker_threads run JavaScript in parallel threads inside the same process and can share memory through SharedArrayBuffer; they suit CPU-heavy tasks like image processing or hashing. cluster forks multiple Node processes that share one server port, each with its own memory and event loop, to use all CPU cores for handling HTTP traffic. In containers, many teams prefer running more replicas instead of cluster.
07

How do you run integration tests against a real database in CI?

Save to ▾
Show answer
Start a disposable database for the test run, using Docker Compose services in CI, Testcontainers from the test code, or mongodb-memory-server for MongoDB. Run migrations before tests, seed minimal data per test, and clean tables between tests or wrap each test in a rolled-back transaction. Use a separate DATABASE_URL so tests can never touch production data.
08

Tell me about a time a database change caused an issue and what you learned.

Save to ▾
Show answer
Situation: I added a NOT NULL column with a default to a large MySQL table during business hours. Task: the migration locked the table and checkout slowed down. Action: I rolled back, rewrote it as add nullable column, backfill in batches, then add the constraint, and ran it at low traffic after testing on a production-size copy. Result: no downtime, and we added a migration review checklist.
09

How do you use the Node.js cluster module to use all CPU cores?

Save to ▾
Show answer
const cluster = require('cluster'); const os = require('os'); if (cluster.isPrimary) { for (let i = 0; i < os.availableParallelism(); i++) cluster.fork(); cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting`); cluster.fork(); }); } else { require('./server'); // each worker listens on the same port } // In Kubernetes, prefer one process per container and more replicas.
10

After a Node.js version upgrade, a few integration tests fail with date and crypto differences. How do you handle the upgrade safely?

Save to ▾
Show answer
Read the release notes and changelog for breaking changes, such as deprecated APIs, OpenSSL updates or changed default behaviour. Run the full test suite on the new version in a CI matrix alongside the old one, fix failures one by one and check native modules rebuild correctly. Roll out to staging, then to a canary in production while watching error rates before upgrading all services.
11

Your API's p99 latency is high during peak hours even though CPU is only 40 percent. What could be wrong?

Save to ▾
Show answer
Low CPU with high latency suggests waiting, not computing. Check database query times and connection pool wait, slow downstream APIs, Redis latency, DNS lookups without keep-alive agents, garbage collection pauses and event loop lag from occasional heavy requests. Use distributed tracing with OpenTelemetry to see where time goes, then add indexes, caching, timeouts or more pool connections.
12

What is database normalisation and when would you denormalise?

Save to ▾
Show answer
Normalisation organises tables to remove duplicate data and update anomalies, typically up to third normal form, for example keeping customers and orders in separate tables linked by foreign keys. You denormalise for read performance, such as storing a product name on an order line or a precomputed order count on a user, when joins become expensive. Denormalised data must be kept in sync.
13

You need to choose between Node.js and Java for a new high-traffic service. How would you decide?

Save to ▾
Show answer
I would look at the workload and team. Node.js fits I/O-heavy services like API gateways, chat, notifications and BFF layers, with fast development and shared JavaScript skills. Java fits CPU-heavy processing, complex multi-threaded logic and teams with strong JVM experience. I would benchmark a prototype for the real access pattern and consider hiring, libraries and existing platform tooling before deciding.
14

Should you use serverless functions like AWS Lambda for a Node.js API?

Save to ▾
Show answer
Serverless suits spiky or low-traffic workloads, event processing and quick prototypes, since you pay per invocation and need no server management. Downsides are cold starts, execution time limits, connection handling with relational databases and harder local debugging. For steady high traffic or long-lived WebSocket connections, containers are usually cheaper and simpler. Many teams mix both.
15

How would you test code that depends on the current time, like an expiring coupon?

Save to ▾
Show answer
Inject a clock function instead of calling Date.now directly, or use Jest fake timers: jest.useFakeTimers().setSystemTime(new Date('2026-01-01')). Then test before, exactly at and after expiry. Store dates in UTC and convert for display in IST, which avoids bugs near midnight. Reset timers after each test with jest.useRealTimers to avoid leaking into other tests.
16

How do you optimise JSON serialisation for very large API responses?

Save to ▾
Show answer
Large JSON.stringify calls block the event loop. Reduce payload size with pagination and field selection first. For unavoidable large outputs, stream the response as NDJSON or a streamed JSON array, use schema-based fast serialisers like fast-json-stringify, which Fastify uses, and cache precomputed responses. Offload heavy transformation to worker threads or background jobs that write files to storage.
17

Your service is expected to get ten times normal traffic during a festive sale. How do you prepare?

Save to ▾
Show answer
Load test at above the expected peak, then fix bottlenecks. Pre-scale instances and database capacity instead of relying only on autoscaling, warm caches, and put static and catalogue responses on a CDN. Add rate limits, queue non-critical work, set timeouts and circuit breakers, prepare feature flags to switch off heavy features, and have dashboards, alerts and an on-call plan ready.
18

Compare Prisma, Sequelize and TypeORM for SQL databases in Node.js.

Save to ▾
Show answer
Prisma uses a schema file to generate a fully typed client and has excellent TypeScript support and migrations, though complex raw SQL needs escape hatches. Sequelize is mature, promise-based and widely used in older JavaScript projects. TypeORM uses decorators and entity classes, familiar to Java and NestJS developers. Drizzle is a newer lightweight, SQL-like typed option. Pick based on TypeScript use and team familiarity.
19

You need to choose a database for a food delivery app's orders, live rider locations and menus. What would you pick?

Save to ▾
Show answer
Orders and payments need strong consistency and transactions, so PostgreSQL or MySQL fits. Live rider locations change every few seconds and need geo queries, so Redis with geospatial commands works well for the hot data, with history stored elsewhere. Menus are read-heavy and nested, so a document store like MongoDB or Postgres JSONB plus caching suits them.
20

Describe a time you led a technical decision that affected the whole team.

Save to ▾
Show answer
Situation: our five Node services used different logging and error formats, making incidents slow to debug. Task: as tech lead I wanted one standard. Action: I wrote a short RFC comparing options, built a shared package with pino, request IDs and an error handler, collected feedback and migrated one service as a pilot. Result: all services adopted it within a month and mean time to resolve incidents fell noticeably.
21

How do you prepare a Node.js app for production readiness review?

Save to ▾
Show answer
I check that config is validated, secrets are in a secret store, and logs are structured with request IDs. Health and readiness endpoints exist, graceful shutdown works, timeouts and retries are set on outbound calls, and rate limiting and helmet are enabled. Dashboards, alerts and runbooks are ready, load tests pass targets, backups are verified and a rollback plan is documented.
22

How would you migrate a monolithic Node.js app to microservices?

Save to ▾
Show answer
Do it gradually with the strangler fig pattern. Identify bounded contexts like auth, catalogue and payments, pick one with clear boundaries and high change rate, extract it behind an API gateway and route traffic to it. Give each service its own data, communicate through APIs and events, and invest in logging, tracing and CI first. Do not split before the monolith causes real pain.
23

How do you load test a Node.js API before a big sale event?

Save to ▾
Show answer
Define targets from expected traffic, such as 5,000 requests per second with p95 under 300 ms. Write realistic scenarios in k6 or Artillery covering browse, cart and checkout, run them against a production-like environment, and ramp up gradually. Watch latency, error rates, CPU, memory, event loop lag and database metrics, then fix bottlenecks and rerun until targets are met with headroom.
24

Describe how you would mentor a junior developer who writes no tests.

Save to ▾
Show answer
I would start by understanding why: lack of time, knowledge or examples. Then I pair with them on one feature, writing a test first for a real bug so they see the value. I share a small template for service and route tests, review their tests kindly in pull requests and celebrate when a test catches a regression. Over a few sprints, testing becomes a habit.
25

An API listing orders became slow after the table reached 50 million rows. How do you investigate?

Save to ▾
Show answer
Run EXPLAIN ANALYZE on the slow query to see whether it does a sequential scan or a costly sort. Add a composite index matching the filter and sort, for example (user_id, created_at DESC). Replace OFFSET pagination with cursor pagination, select only needed columns, and consider partitioning by date and archiving old rows. Monitor slow query logs after the change.
26

What is contract testing and why is it useful for microservices?

Save to ▾
Show answer
Contract testing verifies that a provider API and its consumers agree on request and response formats without running the whole system. With Pact, the consumer writes expectations that become a contract, and the provider runs them in its own CI. It catches breaking changes like a renamed field before deployment, and is faster and less flaky than full end-to-end environments.
27

How do you design an API that needs to handle 50,000 requests per second for reading product details?

Save to ▾
Show answer
Make the read path cache-heavy: CDN caching for public product pages, Redis cache for product details with high hit ratio, and database read replicas behind it. Run many stateless Node instances with autoscaling, keep responses small and compressed, and use keep-alive connections. Avoid cache stampedes with request coalescing or locks, and precompute data that is expensive to build.
28

What is soft delete and what are its trade-offs?

Save to ▾
Show answer
Soft delete marks a record as deleted with a flag or deletedAt timestamp instead of removing it, so data can be restored and audited. Trade-offs: every query must filter out deleted rows, unique constraints need care, tables grow over time and privacy laws such as India's DPDP Act may require real deletion of personal data on request. Use partial indexes and periodic purging.
29

How do you implement real-time features like live order tracking in Node.js?

Save to ▾
Show answer
Use WebSockets through Socket.IO or ws, or Server-Sent Events for one-way updates. Clients join a room per order, and when the rider location or status changes, the server emits to that room. With multiple instances, use the Socket.IO Redis adapter so events reach clients on any server, authenticate the socket on connect, and throttle location updates to save bandwidth.
30

How do you mock a database or external service in Jest?

Save to ▾
Show answer
// order.service.test.js jest.mock('../repositories/orderRepo'); const repo = require('../repositories/orderRepo'); const { cancelOrder } = require('../services/order.service'); test('cannot cancel a shipped order', async () => { repo.findById.mockResolvedValue({ id: 1, status: 'shipped' }); await expect(cancelOrder(1)).rejects.toThrow('Cannot cancel'); expect(repo.update).not.toHaveBeenCalled(); }); // For HTTP calls, nock or msw can intercept requests.
31

How do you use a MongoDB transaction in Mongoose?

Save to ▾
Show answer
const session = await mongoose.startSession(); try { await session.withTransaction(async () => { await Account.updateOne( { _id: fromId, balance: { $gte: amount } }, { $inc: { balance: -amount } }, { session } ); await Account.updateOne({ _id: toId }, { $inc: { balance: amount } }, { session }); await Transfer.create([{ fromId, toId, amount }], { session }); }); } finally { await session.endSession(); } // Requires a replica set or Atlas cluster.
32

What is NoSQL injection in MongoDB and how do you prevent it?

Save to ▾
Show answer
If you pass req.body directly into a query, an attacker can send { "password": { "$ne": null } } and bypass checks. Prevent it by validating and casting input types with zod or Joi, rejecting objects where strings are expected, enabling Mongoose strictQuery and sanitizeFilter, and never building queries from raw user objects. Avoid $where and server-side JavaScript evaluation.
33

What is the MongoDB aggregation pipeline? Give an example.

Save to ▾
Show answer
// Top 5 cities by revenue in the last 30 days const since = new Date(Date.now() - 30 * 864e5); const result = await Order.aggregate([ { $match: { status: 'paid', createdAt: { $gte: since } } }, { $group: { _id: '$city', revenue: { $sum: '$amount' }, orders: { $sum: 1 } } }, { $sort: { revenue: -1 } }, { $limit: 5 } ]); // Each stage transforms documents; put $match early to use indexes.
34

How do you find which function is using the most CPU in a Node.js service?

Save to ▾
Show answer
Reproduce the load with autocannon or k6, then profile with node --cpu-prof to generate a .cpuprofile file and open it in Chrome DevTools, or use clinic flame to get a flame graph. Wide bars show hot functions. Common culprits are JSON.stringify on huge objects, synchronous crypto, regex backtracking and heavy loops. Fix and re-measure under the same load.
35

How do you prevent a cache stampede when a popular key expires?

Save to ▾
Show answer
When a hot key expires, thousands of requests may hit the database at once. Solutions: allow only one request to rebuild the cache using a short Redis lock while others wait or serve stale data, refresh hot keys in the background before expiry, add random jitter to TTLs so keys do not expire together, and use stale-while-revalidate where slightly old data is acceptable.
36

What is backpressure in streams and how does pipeline handle it?

Save to ▾
Show answer
Backpressure happens when a readable source produces data faster than the writable destination can consume it, causing memory to grow. write() returns false when the internal buffer exceeds highWaterMark, and the producer should pause until the drain event. stream.pipeline and pipe handle this automatically, and pipeline also forwards errors and destroys all streams on failure, which pipe does not.
37

A regex in your validation code makes the server hang on certain inputs. What is the issue?

Save to ▾
Show answer
This is likely ReDoS, regular expression denial of service. Patterns with nested quantifiers such as (a+)+ can backtrack exponentially on crafted input, blocking the event loop. Fix by simplifying the regex, limiting input length before matching, using well-tested validators like validator.js, or a linear-time engine such as re2. Add tests with long malicious strings.
38

A test passes locally but fails randomly in CI. How do you approach this flaky test?

Save to ▾
Show answer
Run it repeatedly to reproduce, then look for shared state between tests, missing awaits, reliance on test order, real timers, current date or time zones, random data and network calls. Fix by isolating data per test, using fake timers, freezing dates, mocking external calls and awaiting all promises. Quarantine the test only temporarily with a ticket, never delete it silently.
39

Tell me about a time you had to balance speed of delivery with technical quality.

Save to ▾
Show answer
Situation: sales needed a partner API in one week for a client launch. Task: deliver fast without creating a mess. Action: I agreed with my manager to ship the core endpoints with validation, auth and tests, and to defer caching and admin tooling, logging them as tickets with dates. Result: the partner went live on time, and we completed the deferred work in the next sprint as planned.
40

What are health check endpoints and what is the difference between liveness and readiness?

Save to ▾
Show answer
Health endpoints let orchestrators check the app. Liveness answers whether the process is alive; if it fails, the container is restarted, so keep it simple. Readiness answers whether the instance can serve traffic, checking database and cache connections; if it fails, the load balancer stops sending requests but does not restart it. During shutdown, fail readiness first.

Frequently asked questions

What does a Senior Backend Engineer (Node.js) do?

Owns the design and reliability of backend services at scale. Leads architecture decisions on databases, caching, queues and service boundaries, improves performance and observability, mentors developers and reviews critical code. Handles incidents, capacity planning for traffic spikes and security reviews, and works with product and engineering managers on technical roadmaps.

Which skills are tested in a Senior Backend Engineer (Node.js) interview?

Expect questions on System design, Performance tuning, Microservices, Observability, Mentoring. Most rounds also ask you to explain a project and solve one practical problem live.

How do I prepare for a Senior Backend Engineer (Node.js) interview?

Revise Deployment, Scaling and Performance, Databases: MongoDB, SQL and Redis, Node.js Core and Event Loop, Testing and Debugging first using the topic sheets, practise the questions on this page aloud, then do one full mock interview to practise timing.