MERN Stack Interview Questions for 7 Years Experience
40 questions with answers for candidates with 7 years of experience — 1 easy, 17 medium, 22 hard.
What interviewers expect: 7 years experience
With seven years, you are assessed as a lead or staff engineer. Expect deep system design across services, data modelling for high scale, multi-region availability, cost optimisation and choosing between monolith and microservices. Interviewers want evidence of technical vision, setting engineering standards, improving delivery processes and working with product and business stakeholders on roadmaps and trade-offs.
This set is weighted towards React Hooks, State and Performance (9), Testing, Deployment and DevOps (7), MongoDB and Mongoose (6), Authentication and Security (6).
Distributed system design Engineering standards Technical roadmap Stakeholder management
Solved at this levelStart 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
Create an AuthContext with a provider and a custom hook.
A shallow copy duplicates only the top level, so nested objects are still shared references. Spread syntax and Object.assign make shallow copies. A deep copy duplicates every nested level. structuredClone(obj) is the built-in way in modern browsers and Node.js and supports Dates, Maps and Sets, while JSON.parse(JSON.stringify(obj)) loses functions, undefined and Dates. In React state updates, shallow copies of each changed level are usually enough.
Nginx acts as a reverse proxy and web server. It serves the built React static files efficiently with caching and compression, proxies /api requests to Node instances, load balances across them, terminates HTTPS with certificates such as Let's Encrypt, and can apply rate limits and request size limits. For React Router, it uses try_files with a fallback to index.html so deep links work.
04
How do transactions work in MongoDB and when do you need them?
Single-document writes are already atomic, so good embedded design avoids most transactions. Multi-document ACID transactions are available on replica sets and sharded clusters, not on a standalone server. In Mongoose, start a session, call session.withTransaction() and pass the session to every operation. Use them for cases like transferring wallet balance between two users. They add latency and should stay short, ideally under one second.
05
How do you debug a JavaScript bug that a user reports but you cannot reproduce locally?
Situation: a user reported a checkout button doing nothing, but it worked for me. Task: find the cause quickly. Action: I asked for browser, device and steps, checked our error-tracking logs, and found a TypeError only on an older Safari version due to an unsupported method. I reproduced it on a cloud device, added a polyfill and a test. Result: the fix shipped the same day and I added browser targets to our build.
06
When a user logs out or changes password, how do you make sure their existing JWTs stop working?
Stateless JWTs stay valid until expiry, so keep access tokens short-lived and revoke refresh tokens by deleting or flagging them in the database. For immediate invalidation, store a tokenVersion or passwordChangedAt on the user and include it in the token; the auth middleware rejects tokens with an older version. Alternatively keep a Redis denylist of token ids until they expire. Clear the refresh cookie on logout.
07
What is PM2 and why is it used to run Node.js in production?
PM2 is a process manager for Node.js. It keeps the app alive by restarting it after crashes, runs multiple instances in cluster mode to use all CPU cores, supports zero-downtime reloads with pm2 reload, manages logs and starts apps on server boot. Configuration lives in an ecosystem.config.js file. On container platforms like Kubernetes, the orchestrator often replaces PM2's restart and scaling role.
08
Your React production bundle is 3 MB and the first load is slow on mobile. What steps do you take?
Analyse the bundle to find the largest modules. Split code by route with React.lazy, lazy load heavy libraries like charts and editors, replace large dependencies with lighter ones, import only needed functions so tree shaking works, and remove unused polyfills. Compress images, serve assets from a CDN with Brotli and long cache headers, and consider SSR or static rendering for landing pages. Track Core Web Vitals after each change.
09
Design a secure forgot-password flow for a MERN application.
The user submits an email; always respond with the same message whether or not it exists. Generate a random token with crypto.randomBytes, store only its hash with an expiry of around 15 minutes, and email a link with the raw token. On submission, hash the token, find a matching unexpired record, set the new hashed password, delete the token and invalidate existing sessions. Rate limit the endpoint.
10
What is the EventEmitter class and where is it used?
EventEmitter from the node:events module implements the publish-subscribe pattern. You register listeners with on or once and trigger them with emit, passing data. Many core objects extend it, including HTTP servers, streams and process. Always handle the error event, because an emitted error with no listener crashes the process. Remove listeners you no longer need to avoid the MaxListenersExceededWarning and memory leaks.
11
How does the useEffect dependency array work and why is cleanup important?
useEffect runs after render. With no array it runs after every render, with an empty array only after mount, and with dependencies whenever any of them change by Object.is comparison. The function you return is the cleanup, which runs before the next effect and on unmount. Use it to remove listeners, clear intervals, abort requests and close sockets, otherwise you get leaks and duplicate subscriptions.
12
What are replica sets and sharding in MongoDB, and how do you choose a shard key?
A replica set is a primary plus secondaries holding copies of data, giving automatic failover and optional read scaling. Sharding splits a collection across multiple shards for horizontal scaling of data size and write throughput. A good shard key has high cardinality, evenly distributed writes and matches common queries so they target one shard. Monotonic keys like createdAt create hot spots unless hashed.
It must keep result order and reject on the first failure.
function promiseAll(items) {
return new Promise((resolve, reject) => {
const results = [];
let done = 0;
if (items.length === 0) return resolve(results);
items.forEach((item, i) => {
Promise.resolve(item).then((value) => {
results[i] = value;
done += 1;
if (done === items.length) resolve(results);
}, reject);
});
});
}
Promise.resolve handles plain values mixed with Promises.
14
Your Express API slows down badly during peak traffic. How do you find and fix the bottleneck?
Measure first: add request timing logs or APM tracing to find slow endpoints, then check whether time goes to the database, external calls or CPU. Use explain() for slow queries and add indexes, cache hot read endpoints in Redis, enable compression, paginate large responses and remove synchronous code from handlers. Then scale horizontally with multiple instances behind a load balancer and load test with k6 or autocannon.
15
Write a GitHub Actions workflow that tests and builds a MERN project on every pull request.
Three services on one network:
services:
mongo:
image: mongo:8
volumes:
- mongo-data:/data/db
api:
build: ./server
environment:
MONGO_URI: mongodb://mongo:27017/shop
JWT_SECRET: dev-secret
ports:
- "5000:5000"
depends_on:
- mongo
web:
build: ./client
ports:
- "8080:80"
depends_on:
- api
volumes:
mongo-data:
The API reaches the database through the service name mongo.
17
Users can upload profile pictures and documents. What security measures do you put in place?
Enforce size limits and an allowlist of types, checking magic bytes rather than trusting the extension or Content-Type. Rename files with random ids, store them in object storage outside the web root, and serve them from a separate domain or with Content-Disposition attachment for documents. Strip image metadata, scan for malware where needed, use pre-signed URLs with expiry for private files, and never execute or include uploaded files.
18
Tell me about a time you led a technical migration in a frontend codebase.
Situation: our React app still used Create React App and class components, and builds took several minutes. Task: as the senior developer I proposed moving to Vite and hooks. Action: I wrote a migration plan, moved the build tool first behind a feature branch, fixed environment variable names, then converted components gradually with tests. Result: dev server start went from 40 seconds to 2, builds became much faster, and the team adopted hooks patterns.
19
Explain indexes in MongoDB, compound indexes and the ESR rule.
An index is a sorted structure that lets queries avoid scanning every document. A compound index covers multiple fields in order, like { userId: 1, createdAt: -1 }, and supports queries on its leading prefix. The ESR guideline says order fields as Equality first, then Sort, then Range. Indexes speed reads but slow writes and use memory, so create them for real query patterns and drop unused ones.
20
Write an async helper that retries a failing call with exponential backoff.
Wait longer after each failure and give up after a limit.
async function retry(fn, retries = 3, base = 500) {
for (let attempt = 0; ; attempt++) {
try {
return await fn();
} catch (err) {
if (attempt >= retries) throw err;
const wait = base * 2 ** attempt + Math.random() * 100;
await new Promise((r) => setTimeout(r, wait));
}
}
}
The random jitter stops many clients from retrying at the same moment.
21
An error in one dashboard widget crashes the entire React page. How do you contain it?
Wrap risky sections in error boundaries. An error boundary catches rendering errors in its subtree and shows fallback UI instead of unmounting the whole app. React still requires a class with getDerivedStateFromError and componentDidCatch, or you can use the react-error-boundary package. Place boundaries around each widget and the route level, log errors to monitoring, and offer a retry. They do not catch errors in event handlers or async code.
22
What is a custom hook and what rules must hooks follow?
A custom hook is a function whose name starts with use and that calls other hooks to package reusable stateful logic, such as useFetch, useDebounce or useAuth. Each component using it gets its own state. Hooks must be called at the top level of a component or another hook, never inside conditions, loops or nested functions, so React can match state by call order. The eslint-plugin-react-hooks rules enforce this.
23
Write a Redux Toolkit slice that fetches products with createAsyncThunk.
An unbounded embedded array risks hitting the 16 MB document limit and makes every post read and update heavy. Move comments to their own collection with a postId field and an index on { postId: 1, createdAt: -1 }, then paginate. Optionally keep a small embedded array of the latest few comments plus a commentCount on the post for fast first render. This is the subset pattern.
25
You need to call an external API 500 times but it allows only 5 concurrent requests. How would you implement this?
Use a concurrency-limited queue. Keep a pool of five workers; each worker picks the next item from a shared index, awaits the request, and loops until the list is exhausted. Run the workers with Promise.all. Libraries such as p-limit do this neatly. Add retries with backoff for 429 responses and collect failures separately instead of failing the whole batch, so one bad item does not stop the job.
26
How do you handle pressure to ship quickly when you think a feature is not secure yet?
Situation: a product manager wanted a file-sharing feature live by Friday, but uploads had no type or access checks. Task: protect users without blocking the launch. Action: I explained the risk in business terms, proposed shipping with private pre-signed links and type limits first, and deferring sharing features to the next sprint. Result: we launched on time with the risky part removed, and the full feature followed a week later.
27
What is CSRF and how do SameSite cookies help prevent it?
Cross-site request forgery tricks a logged-in user's browser into sending a request to your site from a malicious page, and the browser attaches the user's cookies automatically. SameSite=Lax blocks cookies on cross-site POST requests and SameSite=Strict blocks them on all cross-site requests, which stops most CSRF. For extra safety use CSRF tokens on state-changing routes, never change state with GET, and verify the Origin header.
28
A setInterval inside useEffect always logs the initial count value instead of the updated one. Why, and how do you fix it?
This is a stale closure: the effect ran once with an empty dependency array, so its callback captured count from the first render forever. Fixes include using the functional updater setCount((c) => c + 1) so you do not need to read count, adding count to the dependencies with proper cleanup, or storing the latest value in a ref that the interval reads.
29
How would you use Redis caching in a MERN backend and what are the pitfalls?
Use the cache-aside pattern: check Redis for a key, return it on a hit, otherwise query MongoDB, store the result with a TTL and return it. Good targets are expensive, frequently read data like product listings. Pitfalls include stale data, so invalidate or update keys on writes; cache stampede when many requests miss at once, solved with locking or early refresh; and memory limits, managed with eviction policies.
30
Create a compound index for a user's order history query and verify it is used.
Query: orders of one user, newest first.
db.orders.createIndex({ userId: 1, createdAt: -1 })
db.orders.find({ userId: ObjectId('...') })
.sort({ createdAt: -1 })
.limit(20)
.explain('executionStats')
Check that the winning plan shows IXSCAN, not COLLSCAN, and that totalDocsExamined is close to nReturned. In Mongoose, declare it with orderSchema.index({ userId: 1, createdAt: -1 }).
31
Users must upload files up to 200 MB. How would you handle this in a MERN application?
Avoid buffering big files in the API server's memory. The best approach is to have the backend generate a pre-signed URL for object storage such as S3, then let the React client upload directly to storage, with multipart upload for large files. If uploads must go through Express, use multer with disk storage or stream to storage, enforce size and type limits, and save only metadata in MongoDB.
32
How do you implement graceful shutdown for a Node.js API during deployments?
Listen for SIGTERM and SIGINT. When received, stop accepting new connections with server.close(), let in-flight requests finish, close database connections with mongoose.connection.close() and other resources, then exit with code 0. Set a timeout, for example 10 seconds, after which you force exit. In Kubernetes or behind a load balancer, also fail the readiness check first so traffic stops reaching the instance.
33
Compare worker_threads, cluster and child_process in Node.js.
cluster forks multiple Node processes that share one server port, used to use all CPU cores for an HTTP app, though PM2 or containers often do this instead. child_process runs a separate program or script, for example ffmpeg, communicating through stdio or IPC. worker_threads run JavaScript in parallel threads inside one process and can share memory through SharedArrayBuffer, best for CPU-heavy tasks like image processing or parsing.
React.memo wraps a component so it skips re-rendering when its props are shallowly equal to the previous props. It helps with expensive components that re-render often because the parent re-renders, such as rows in a large table. It fails if you pass new object, array or function props every render, so pair it with useMemo and useCallback. Measure with React DevTools Profiler before adding it.
35
What are Mongoose middleware hooks and give a common use case.
Mongoose middleware are functions that run before or after operations such as save, validate, deleteOne, findOneAndUpdate and aggregate. A classic pre-save hook hashes a password only if it was modified: if (!this.isModified('password')) return; this.password = await bcrypt.hash(this.password, 12). Post hooks are used for logging or syncing. Note that query middleware like findOneAndUpdate does not trigger save hooks.
36
How do you plan a Node.js major version upgrade for a project your team maintains?
Situation: our services were on a Node version nearing end of life. Task: I owned the upgrade to the current LTS. Action: I read the changelog for breaking changes, upgraded locally, ran the test suite, fixed deprecated APIs and incompatible native packages, and rolled out to staging, then one production service, watching metrics. Result: all services moved within two sprints with no incidents, and I added an LTS calendar to our planning.
37
Memory usage of a production Node.js service keeps rising until it restarts. How do you investigate?
First confirm the trend with monitoring of heapUsed and RSS. Reproduce in staging under load, then take heap snapshots with --inspect and Chrome DevTools, or use --heapsnapshot-signal, and compare snapshots to find growing object types and their retainers. Common causes are unbounded in-memory caches, listeners added per request, global arrays and unclosed timers. Fix the root cause, add a bounded LRU cache, and set alerts.
38
Write a production Dockerfile for a Node.js Express API.
Keep the image small and run as a non-root user.
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY src ./src
USER node
EXPOSE 5000
CMD ["node", "src/server.js"]
Copying package files first lets Docker cache the dependency layer, so code changes rebuild quickly. Add a .dockerignore with node_modules and .env.
39
What logging and monitoring should a production MERN app have?
Use structured JSON logs with a fast logger like pino, including a request id to trace a request across services, and ship logs to a central system. Track metrics such as request rate, error rate, latency percentiles, event-loop lag, memory and database performance, with dashboards and alerts. Add error tracking for both React and Node, uptime checks and distributed tracing with OpenTelemetry for microservices.
40
Compare session-based authentication with JWT-based authentication.
With sessions, the server stores session data in a store such as Redis and the browser holds only a session id cookie; revoking is easy, but every request needs a lookup. With JWTs, the token itself carries signed claims, so servers can verify it without a lookup, which suits microservices and mobile clients. JWTs are harder to revoke before expiry, so keep them short-lived and pair them with refresh tokens.
Frequently asked questions
What is asked in MERN Stack interviews for 7 years of experience?
With seven years, you are assessed as a lead or staff engineer. Expect deep system design across services, data modelling for high scale, multi-region availability, cost optimisation and choosing between monolith and microservices. Interviewers want evidence of technical vision, setting engineering standards, improving delivery processes and working with product and business stakeholders on roadmaps and trade-offs.
How many questions should I practise before a MERN Stack interview?
Work through all 40 questions here, then the company-wise sets for the employers you are targeting. Quality matters more than count: be able to explain why each answer is right.
Which topics matter most for 7 years of experience?
Focus first on Distributed system design, Engineering standards, Technical roadmap, Stakeholder management.