Skip to content

Top 50 Most Asked Full Stack with Node.js Interview Questions

The questions that appear most often across company-wise sets — master these first.

Why start here

We count how often each question appears across the 20 company-wise Full Stack with Node.js practice sets on this site and show the 50 most common. They are the safest questions to master first.

Solved — top 50Start 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

How would you handle uncaughtException and unhandledRejection in production?

Node.js Core and Event LoopIn 11 company setsMedium
Save to ▾
Show answer
Log both with full stack traces and context, then exit the process after flushing logs, because state may be corrupted. A process manager like PM2, systemd or Kubernetes restarts it. Never use uncaughtException to keep running as if nothing happened. Since Node 15, unhandled rejections crash the process by default, so every promise chain should have proper error handling.
02

How do you add a timeout to a promise?

Asynchronous JavaScriptIn 9 company setsMedium
Save to ▾
Show answer
function withTimeout(promise, ms) { let timer; const timeout = new Promise((_, reject) => { timer = setTimeout(() => reject(new Error('Timeout')), ms); }); return Promise.race([promise, timeout]).finally(() => clearTimeout(timer)); } await withTimeout(fetch(url), 3000); // For fetch, AbortSignal.timeout(3000) also cancels the request.
03

How do you implement rate limiting on a login endpoint?

Authentication and SecurityIn 9 company setsMedium
Save to ▾
Show answer
const rateLimit = require('express-rate-limit'); const { RedisStore } = require('rate-limit-redis'); const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, limit: 5, standardHeaders: 'draft-7', legacyHeaders: false, keyGenerator: (req) => `${req.ip}:${req.body.email}`, store: new RedisStore({ sendCommand: (...a) => redis.sendCommand(a) }) }); app.post('/auth/login', loginLimiter, login); // Add account lockout or CAPTCHA after repeated failures.
04

Implement the cache-aside pattern with Redis for a product lookup.

Databases: MongoDB, SQL and RedisIn 9 company setsMedium
Save to ▾
Show answer
async function getProduct(id) { const key = `product:${id}`; const cached = await redis.get(key); if (cached) return JSON.parse(cached); const product = await Product.findById(id).lean(); if (product) { await redis.set(key, JSON.stringify(product), { EX: 300 }); } return product; } async function updateProduct(id, data) { await Product.updateOne({ _id: id }, data); await redis.del(`product:${id}`); // invalidate }
05

What is the difference between throwing an error and rejecting a promise inside an async function?

Asynchronous JavaScriptIn 8 company setsMedium
Save to ▾
Show answer
Inside an async function they behave the same: throw new Error() causes the returned promise to reject with that error. Outside async functions, a throw inside a plain callback such as setTimeout is not caught by promise handlers and becomes an uncaught exception. Always reject with Error objects, not strings, so you keep a stack trace.
06

Write a Dockerfile for a production Node.js API.

Save to ▾
Show answer
FROM node:22-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev FROM node:22-alpine ENV NODE_ENV=production WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . USER node EXPOSE 3000 HEALTHCHECK CMD wget -qO- http://localhost:3000/health || exit 1 CMD ["node", "src/server.js"]
07

Write a basic GitHub Actions workflow that tests and builds a Node.js app.

Save to ▾
Show answer
name: ci on: [push, pull_request] jobs: test: runs-on: ubuntu-latest services: mongo: image: mongo:7 ports: ['27017:27017'] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - run: npm ci - run: npm run lint - run: npm test -- --coverage env: MONGO_URL: mongodb://localhost:27017/test
08

How do you implement graceful shutdown in a Node.js server?

Node.js Core and Event LoopIn 7 company setsMedium
Save to ▾
Show answer
const server = app.listen(3000); async function shutdown(signal) { console.log(signal, 'received, closing'); server.close(async () => { await db.close(); await redis.quit(); process.exit(0); }); setTimeout(() => process.exit(1), 10000).unref(); } process.on('SIGTERM', shutdown); process.on('SIGINT', shutdown); // Stops new connections, finishes in-flight requests, closes pools.
09

A dashboard endpoint makes five independent database queries one after another and takes 1.5 seconds. How would you speed it up?

Asynchronous JavaScriptIn 7 company setsMedium
Save to ▾
Show answer
Because the queries are independent, run them concurrently with Promise.all so total time is close to the slowest query instead of the sum. Check that the database connection pool is large enough to serve them in parallel. Then add indexes for slow queries, cache rarely changing parts in Redis, and use Promise.allSettled if the page can render with some widgets missing.
10

You must change a response field name used by many clients. How do you do it without breaking them?

REST API DesignIn 7 company setsMedium
Save to ▾
Show answer
Treat it as a breaking change. Option one: add the new field alongside the old one, mark the old field deprecated in docs and response headers, track usage through logs and remove it after clients migrate. Option two: release it in /v2 and keep /v1 for a deprecation window. Communicate timelines clearly and add contract tests for both.
11

Tell me about a time you found a security issue in code and how you handled it.

Authentication and SecurityIn 7 company setsMedium
Save to ▾
Show answer
Situation: during code review I noticed an admin export route that only hid the button in the frontend. Task: make sure no regular user could call it. Action: I reproduced it with a normal user token, reported it privately to my lead, added role middleware and tests, and checked similar routes. Result: we fixed four endpoints before release and added an authorisation checklist to pull requests.
12

A Mongoose query returns large documents and the API is slow. What optimisations can you apply?

Databases: MongoDB, SQL and RedisIn 7 company setsMedium
Save to ▾
Show answer
Use .select() to fetch only needed fields, and .lean() to return plain objects instead of full Mongoose documents, which cuts memory and CPU. Make sure the filter and sort use an index, checked with explain. Paginate results, avoid populating deep references, and cache frequently read data. For large exports, use a cursor with for await instead of loading everything.
13

What is the difference between process.nextTick and setImmediate?

Node.js Core and Event LoopIn 6 company setsMedium
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.
14

How do you serve a React build and an API from the same Express server?

Express.js FrameworkIn 6 company setsMedium
Save to ▾
Show answer
const path = require('path'); app.use('/api', apiRouter); app.use(express.static(path.join(__dirname, 'client/dist'), { maxAge: '1y' })); // SPA fallback for client-side routes app.get(/^\/(?!api).*/, (req, res) => { res.sendFile(path.join(__dirname, 'client/dist/index.html')); }); // Register API routes first so they are not caught by the fallback.
15

How do you design Express middleware that checks user roles for a route?

Express.js FrameworkIn 6 company setsMedium
Save to ▾
Show answer
Create a factory: const authorize = (...roles) => (req, res, next) => roles.includes(req.user?.role) ? next() : res.status(403).json({ error: 'Forbidden' }). Use it after authentication, for example router.delete('/:id', authenticate, authorize('admin'), handler). Keep roles and permissions in config or the database, and for complex rules move to permission-based checks or a policy library.
16

Compare offset pagination and cursor pagination.

REST API DesignIn 6 company setsMedium
Save to ▾
Show answer
Offset pagination uses page and limit, translated to LIMIT and OFFSET. It is simple and allows jumping to a page, but gets slow on large tables and can skip or repeat rows when data changes. Cursor pagination uses the last seen value, such as id or created_at, to fetch the next set with a WHERE clause. It is fast and stable, ideal for feeds and infinite scroll.
17

How do you implement and secure webhooks that your API sends to customers?

REST API DesignIn 6 company setsHard
Save to ▾
Show answer
Send a POST with a JSON event, a unique event ID and timestamp. Sign the body with HMAC-SHA256 using a per-customer secret and include it in a header, so receivers verify authenticity and reject old timestamps to stop replays. Retry failures with exponential backoff, log delivery attempts and make events idempotent so receivers can safely handle duplicates.
18

How would you add OTP-based login for an Indian mobile app?

Authentication and SecurityIn 6 company setsMedium
Save to ▾
Show answer
Generate a random 6-digit OTP with crypto.randomInt, store only its hash in Redis with a 5-minute TTL and an attempt counter, and send it through an SMS provider on a DLT-registered template. Verify with a timing-safe compare, limit to about 3 to 5 attempts and rate limit sends per number and IP. On success, issue access and refresh tokens and delete the OTP.
19

npm audit reports a critical vulnerability in a dependency of a dependency. What do you do?

Authentication and SecurityIn 6 company setsMedium
Save to ▾
Show answer
First check whether the vulnerable code path is actually reachable in our usage and read the advisory. Try npm audit fix or updating the parent package to a version that pulls a patched sub-dependency. If none exists, use the overrides field in package.json to force a safe version and run tests. Track it in a ticket and enable Dependabot or Renovate for ongoing updates.
20

What is a compound index and why does field order matter?

Databases: MongoDB, SQL and RedisIn 6 company setsMedium
Save to ▾
Show answer
A compound index covers multiple fields, such as { userId: 1, createdAt: -1 }. It supports queries that use a prefix of the fields, so it helps queries on userId alone or userId plus createdAt, but not createdAt alone. A good rule in MongoDB is ESR: put equality fields first, then sort fields, then range fields, to avoid in-memory sorts.
21

What is the MongoDB aggregation pipeline? Give an example.

Databases: MongoDB, SQL and RedisIn 6 company setsMedium
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.
22

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

Databases: MongoDB, SQL and RedisIn 6 company setsMedium
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.
23

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.
24

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.
25

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.
26

What is an API gateway and what does it do in a Node.js microservice setup?

Save to ▾
Show answer
An API gateway is a single entry point in front of services. It routes requests, terminates TLS, validates tokens, applies rate limits, handles CORS, aggregates responses and collects logs and metrics. Examples are Kong, AWS API Gateway, Nginx and Envoy-based gateways. It keeps cross-cutting concerns out of each service, but must be highly available so it does not become a single point of failure.
27

How do you read a large file efficiently in Node.js?

Node.js Core and Event LoopIn 5 company setsMedium
Save to ▾
Show answer
const fs = require('fs'); const readline = require('readline'); async function countErrors(path) { const rl = readline.createInterface({ input: fs.createReadStream(path), crlfDelay: Infinity }); let count = 0; for await (const line of rl) { if (line.includes('ERROR')) count++; } return count; } // Streams line by line, so a 5 GB log uses little memory.
28

Your Node.js API becomes unresponsive when one endpoint generates a large PDF report. What is happening and how do you fix it?

Node.js Core and Event LoopIn 5 company setsMedium
Save to ▾
Show answer
The PDF generation is CPU-bound and blocks the single event loop, so every other request waits. Fixes: move the work to a worker_threads pool such as Piscina, or push it to a background job queue like BullMQ with Redis and return a job ID that the client polls. Also break large loops into chunks and measure event loop lag to confirm the fix.
29

Explain the difference between Promise.all, Promise.allSettled, Promise.race and Promise.any.

Asynchronous JavaScriptIn 5 company setsMedium
Save to ▾
Show answer
Promise.all resolves with all results when every promise fulfils, and rejects as soon as one rejects. Promise.allSettled waits for all and returns each status and value or reason, useful when partial failure is fine. Promise.race settles with the first promise to settle, often used for timeouts. Promise.any resolves with the first fulfilled promise and rejects only if all reject.
30

How does async/await work under the hood?

Asynchronous JavaScriptIn 5 company setsMedium
Save to ▾
Show answer
An async function always returns a promise. await pauses that function until the awaited promise settles, then resumes it with the value or throws the rejection, while the event loop keeps running other work. Internally it is built on promises and generator-like suspension. The code reads like synchronous code but is still non-blocking, and errors are handled with ordinary try/catch.
31

What are microtasks and macrotasks?

Asynchronous JavaScriptIn 5 company setsMedium
Save to ▾
Show answer
Macrotasks are scheduled work like setTimeout, setInterval, setImmediate and I/O callbacks, handled phase by phase by the event loop. Microtasks are promise reactions and queueMicrotask callbacks; they run right after the current synchronous code finishes and before the next macrotask. In Node, process.nextTick callbacks run even before promise microtasks. A long microtask chain can delay timers and I/O.
32

How do you limit concurrency when calling an external API for 10,000 records?

Asynchronous JavaScriptIn 5 company setsHard
Save to ▾
Show answer
async function runLimited(items, limit, worker) { const results = []; let i = 0; async function next() { while (i < items.length) { const idx = i++; results[idx] = await worker(items[idx]); } } await Promise.all(Array.from({ length: limit }, next)); return results; } await runLimited(records, 10, callPartnerApi); // Or use the p-limit package.
33

How do you validate request bodies in Express?

Express.js FrameworkIn 5 company setsMedium
Save to ▾
Show answer
const { z } = require('zod'); const createUser = z.object({ name: z.string().min(2), email: z.string().email(), age: z.number().int().min(18).optional() }); const validate = (schema) => (req, res, next) => { const r = schema.safeParse(req.body); if (!r.success) return res.status(400).json({ errors: r.error.issues }); req.body = r.data; next(); }; router.post('/users', validate(createUser), createUserHandler);
34

Implement cursor-based pagination for a products endpoint.

REST API DesignIn 5 company setsMedium
Save to ▾
Show answer
router.get('/products', async (req, res) => { const limit = Math.min(Number(req.query.limit) || 20, 100); const cursor = req.query.cursor; const filter = cursor ? { _id: { $lt: cursor } } : {}; const items = await Product.find(filter) .sort({ _id: -1 }) .limit(limit + 1); const hasMore = items.length > limit; if (hasMore) items.pop(); res.json({ data: items, nextCursor: hasMore ? items[items.length - 1]._id : null }); });
35

How do you implement filtering and sorting safely from query parameters?

REST API DesignIn 5 company setsMedium
Save to ▾
Show answer
const ALLOWED_SORT = ['price', 'createdAt', 'name']; router.get('/products', async (req, res) => { const filter = {}; if (req.query.category) filter.category = String(req.query.category); if (req.query.maxPrice) filter.price = { $lte: Number(req.query.maxPrice) }; const field = ALLOWED_SORT.includes(req.query.sort) ? req.query.sort : 'createdAt'; const dir = req.query.order === 'asc' ? 1 : -1; res.json(await Product.find(filter).sort({ [field]: dir }).limit(50)); }); // Whitelist fields and cast types to block injection.
36

Where should a web app store tokens: localStorage or cookies?

Authentication and SecurityIn 5 company setsMedium
Save to ▾
Show answer
localStorage is readable by any JavaScript on the page, so an XSS bug can steal tokens. HttpOnly, Secure, SameSite cookies cannot be read by JavaScript, which is safer for refresh tokens and session IDs. Cookies require CSRF protection, which SameSite=Lax or Strict plus CSRF tokens provide. A common pattern keeps the access token in memory and the refresh token in an HttpOnly cookie.
37

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

Authentication and SecurityIn 5 company setsMedium
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.
38

Users report seeing stale prices after an update because of caching. How do you solve it?

Databases: MongoDB, SQL and RedisIn 5 company setsMedium
Save to ▾
Show answer
Invalidate or update the cache key in the same code path that updates the price, preferably after the database commit. Use reasonable TTLs as a safety net, and version keys if needed. If several services update prices, publish a price-changed event and have consumers delete the cache. For CDN-cached responses, purge the relevant URLs or use short max-age with stale-while-revalidate.
39

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.
40

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

Testing and DebuggingIn 5 company setsMedium
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.
41

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

Testing and DebuggingIn 5 company setsMedium
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.
42

How do you use a message queue to process background jobs in Node.js?

Save to ▾
Show answer
const { Queue, Worker } = require('bullmq'); const connection = { host: 'redis', port: 6379 }; const emailQueue = new Queue('email', { connection }); await emailQueue.add('welcome', { userId }, { attempts: 5, backoff: { type: 'exponential', delay: 1000 }, jobId: `welcome:${userId}` }); new Worker('email', async (job) => { await sendWelcomeEmail(job.data.userId); }, { connection, concurrency: 10 });
43

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.
44

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.
45

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.
46

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

Node.js Core and Event LoopIn 4 company setsHard
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.
47

Write a retry function with exponential backoff for a flaky API call.

Asynchronous JavaScriptIn 4 company setsMedium
Save to ▾
Show answer
async function retry(fn, retries = 3, baseMs = 200) { for (let attempt = 0; ; attempt++) { try { return await fn(); } catch (err) { if (attempt >= retries) throw err; const delay = baseMs * 2 ** attempt + Math.random() * 100; await new Promise((r) => setTimeout(r, delay)); } } } await retry(() => paymentClient.getStatus(id));
48

Your service calls three microservices and fails completely if one is down. How would you make it more resilient?

Asynchronous JavaScriptIn 4 company setsHard
Save to ▾
Show answer
Use Promise.allSettled so one failure does not reject everything, and return partial data with clear flags. Add timeouts to every call, retries with backoff for transient errors and a circuit breaker such as opossum to stop hammering a failing service. Provide fallbacks like cached values and log failures with correlation IDs so the issue can be traced.
49

A scheduled job processes orders with setInterval every minute, but sometimes runs overlap and duplicate emails are sent. How do you fix it?

Asynchronous JavaScriptIn 4 company setsMedium
Save to ▾
Show answer
setInterval fires regardless of whether the previous async run finished. Use a recursive setTimeout that schedules the next run only after the current one completes, or keep an isRunning flag. If several instances run, use a distributed lock in Redis or a job queue like BullMQ with unique job IDs. Also make email sending idempotent by recording sent message IDs.
50

Explain debounce and throttle and where they matter on the backend.

Asynchronous JavaScriptIn 4 company setsMedium
Save to ▾
Show answer
Debounce runs a function only after calls stop for a set time, merging bursts into one call. Throttle runs it at most once per interval. On the backend they help when batching cache invalidation, limiting webhook processing, writing metrics, or reacting to file watcher events. For API traffic you normally use a rate limiter instead, which is a server-side form of throttling.

Frequently asked questions

How is this list made?

We count how often each question appears across the 20 company-wise Full Stack with Node.js practice sets on this site and show the 50 most common. They are the safest questions to master first.

Is this enough to clear an interview?

It is the best starting point, not the finish line. After these, practise the company pages for your target employers and the sheets for your weaker topics.