Skip to content

Full Stack JavaScript Developer Interview Questions & Answers

40 questions for Full Stack JavaScript Developer interviews — 4 easy, 30 medium, 6 hard.

About the Full Stack JavaScript Developer role

A Full Stack JavaScript Developer with two to five years of experience owns features end to end and makes design decisions on both sides. You plan data models, API contracts and frontend state together, review code, write tests and handle deployments. Companies expect you to balance speed with quality, debug across layers, and support juniors while delivering modules independently and on schedule.

Feature ownership API design React performance Automated testing CI/CD
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 aggregation pipeline and what are its common stages?

Save to ▾
Show answer
The aggregation pipeline processes documents through a sequence of stages, each transforming the stream. Common stages are $match to filter, $group to aggregate with operators like $sum and $avg, $project or $addFields to shape fields, $sort, $limit, $skip, $lookup to join another collection, $unwind to flatten arrays and $facet for multiple outputs. Put $match and $sort early so they can use indexes and reduce the data volume.
02

Users must upload files up to 200 MB. How would you handle this in a MERN application?

Save to ▾
Show answer
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.
03

Write a reusable validation middleware for Express using zod.

Save to ▾
Show answer
Validate before the controller runs and return 400 on failure. import { z } from 'zod'; const validate = (schema) => (req, res, next) => { const result = schema.safeParse(req.body); if (!result.success) { return res.status(400).json({ errors: result.error.issues }); } req.body = result.data; next(); }; const userSchema = z.object({ name: z.string().min(2), email: z.string().email() }); router.post('/users', validate(userSchema), createUser);
04

Write an aggregation that counts orders and sums revenue per status.

Save to ▾
Show answer
Group by status and sort by revenue. db.orders.aggregate([ { $match: { createdAt: { $gte: ISODate('2026-01-01') } } }, { $group: { _id: '$status', orders: { $sum: 1 }, revenue: { $sum: '$amount' } } }, { $sort: { revenue: -1 } }, { $project: { status: '$_id', orders: 1, revenue: 1, _id: 0 } } ]) In Mongoose the same array goes into Order.aggregate([...]).
05

How is Docker used in a MERN project?

Save to ▾
Show answer
Docker packages each service with its runtime and dependencies into an image so it runs the same on every machine. Typically the Express API gets an image built from a Node base, the React app is built and served by Nginx, and MongoDB runs from the official image locally while production often uses MongoDB Atlas. docker compose starts all services with one command, with networks and volumes for persistent data.
06

What is the Context API and when should you avoid it?

Save to ▾
Show answer
Context passes data through the component tree without prop drilling. You create it with createContext, provide a value with a Provider and read it with useContext, or the newer use API. It suits low-frequency global data like theme, language and logged-in user. Avoid it for frequently changing large state, because every consumer re-renders when the value changes; split contexts or use Zustand or Redux Toolkit instead.
07

What is the difference between server state and client state, and why use a library like TanStack Query?

Save to ▾
Show answer
Client state is UI data owned by the browser, like modal open or selected tab. Server state lives in the database, can be changed by others, and is only a cached copy in the browser. TanStack Query manages server state with caching, deduplication, background refetching, retries, pagination and mutations with cache invalidation. This removes much hand-written useEffect fetching and stops global stores from holding stale API data.
08

What does lean() do in Mongoose and when should you use it?

Save to ▾
Show answer
By default Mongoose queries return full documents with change tracking, getters, virtuals and methods like save. Calling .lean() returns plain JavaScript objects, which uses much less memory and is noticeably faster. Use it for read-only endpoints such as lists and API responses. Skip it when you need to modify and save the document, or depend on virtuals and getters unless you add a lean plugin.
09

An error in one dashboard widget crashes the entire React page. How do you contain it?

Save to ▾
Show answer
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.
10

Write an Express router with CRUD routes for a products resource.

Save to ▾
Show answer
Keep routes thin and delegate to a controller. import { Router } from 'express'; import * as ctrl from '../controllers/product.controller.js'; const router = Router(); router.get('/', ctrl.list); router.get('/:id', ctrl.getById); router.post('/', ctrl.create); router.patch('/:id', ctrl.update); router.delete('/:id', ctrl.remove); export default router; // app.js app.use(express.json()); app.use('/api/v1/products', router);
11

How would you achieve zero-downtime deployments for an Express API?

Save to ▾
Show answer
Run at least two instances behind a load balancer and use rolling or blue-green deployments: start new instances, wait for health and readiness checks to pass, shift traffic, then drain and stop old instances with graceful shutdown. PM2 reload or Kubernetes rolling updates handle this. Keep database migrations backward compatible, adding fields before code uses them, so old and new versions can run together.
12

How would you explain a technical decision, such as choosing REST over GraphQL, to a non-technical manager?

Save to ▾
Show answer
Situation: my manager asked why we were not using GraphQL like a competitor. Task: explain without jargon. Action: I compared it to ordering from a fixed menu versus a custom kitchen, explained that our screens need simple, predictable data, and that REST meant faster delivery with our team's current skills, lower risk and easier caching. Result: the manager approved the plan and we revisited the idea later.
13

Some tests pass locally but fail randomly in CI. How do you handle flaky tests?

Save to ▾
Show answer
Rerun to confirm flakiness, then find the cause instead of adding retries. Common causes are shared database state between tests, tests depending on run order, real timers and dates, network calls to real services, and E2E tests using fixed waits instead of waiting for elements. Isolate data per test, mock time and external APIs, use proper async waits, and quarantine a flaky test with a ticket until fixed.
14

What does a CI/CD pipeline for a MERN application usually include?

Save to ▾
Show answer
On every pull request, continuous integration installs dependencies with npm ci, runs lint, type checks, unit and integration tests, and builds the frontend. On merge to main, continuous delivery builds Docker images or artifacts, tags them with the commit, pushes to a registry, deploys to staging, runs smoke tests and then promotes to production, often with manual approval. GitHub Actions, GitLab CI and Jenkins are common tools.
15

When should you embed documents and when should you reference them in MongoDB?

Save to ▾
Show answer
Embed when data is read together, belongs to one parent, and is bounded in size, such as addresses inside a user or line items inside an order. Reference with ObjectIds when the related data is large, grows without limit, is shared by many documents or is updated independently, such as products referenced by many orders. The rule is to design for your application's query patterns, not for normalisation.
16

What is the difference between req.params, req.query and req.body?

Save to ▾
Show answer
req.params holds named route segments, so for /users/:id a request to /users/42 gives req.params.id equal to '42'. req.query holds the query string, so ?page=2&sort=name gives { page: '2', sort: 'name' }. req.body holds the parsed request payload, available only after a parser like express.json(). Params and query values are strings, so convert and validate them before use.
17

Write a GitHub Actions workflow that tests and builds a MERN project on every pull request.

Save to ▾
Show answer
Run server and client jobs in parallel. name: ci on: pull_request: push: branches: [main] jobs: server: runs-on: ubuntu-latest defaults: run: working-directory: server steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm cache-dependency-path: server/package-lock.json - run: npm ci - run: npm run lint - run: npm test client: runs-on: ubuntu-latest defaults: run: working-directory: client steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm ci - run: npm run build
18

What is CORS and how do you configure it in an Express API?

Save to ▾
Show answer
CORS is a browser security mechanism that blocks a page from reading responses from a different origin unless the server allows it through headers like Access-Control-Allow-Origin. For non-simple requests the browser sends a preflight OPTIONS request first. In Express, use the cors package with an explicit allowlist, for example cors({ origin: ['https://app.example.com'], credentials: true }), instead of allowing every origin with credentials.
19

What are Mongoose middleware hooks and give a common use case.

Save to ▾
Show answer
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.
20

How have you helped junior developers improve their React skills?

Save to ▾
Show answer
Situation: two freshers joined my team and their PRs had repeated effect bugs. Task: help them ramp up without slowing the sprint. Action: I ran short weekly sessions on effects, keys and state structure, paired with them on real tickets, and wrote a review checklist. I gave specific, kind comments in reviews. Result: within two months their PRs needed far fewer changes, and one of them now runs the sessions.
21

How do you implement code splitting in a React app?

Save to ▾
Show answer
Use dynamic import with React.lazy, for example const Admin = lazy(() => import('./Admin')), and wrap it in a Suspense boundary with a fallback. Bundlers like Vite then create a separate chunk that loads only when needed. Split by route first, then by heavy components like charts, editors and maps. Preload likely next routes on hover, and check results with a bundle analyser such as rollup-plugin-visualizer.
22

Your Express API slows down badly during peak traffic. How do you find and fix the bottleneck?

Save to ▾
Show answer
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.
23

Compare offset-based and cursor-based pagination for an API.

Save to ▾
Show answer
Offset pagination uses page and limit, translating to skip and limit in MongoDB. It is simple and allows jumping to page 10, but gets slower on large collections and can skip or repeat items when data changes. Cursor pagination returns items after a stable sorted value, such as the last _id or createdAt, using an indexed range query. It stays fast and consistent, ideal for infinite scroll feeds.
24

What are the core principles of a RESTful API, and which HTTP methods are idempotent?

Save to ▾
Show answer
REST models data as resources identified by URLs, uses standard HTTP methods, is stateless, and returns representations like JSON with proper status codes. Use nouns, for example GET /orders and POST /orders. GET, PUT, DELETE, HEAD and OPTIONS are idempotent: repeating them gives the same server state. POST is not idempotent, and PATCH usually is not, which matters when clients retry requests.
25

Walk me through a MERN project you built, end to end.

Save to ▾
Show answer
Situation: I built a job portal as my major project. Task: let recruiters post jobs and students apply with resumes. Action: I designed MongoDB collections for users, jobs and applications with indexes, built an Express REST API with JWT auth and role checks, a React frontend with React Router and TanStack Query, uploaded resumes to cloud storage, wrote API tests and deployed with Docker. Result: 60 classmates used it during placement season.
26

What is a custom hook and what rules must hooks follow?

Save to ▾
Show answer
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.
27

How would you structure the folders of a production Express API?

Save to ▾
Show answer
A layered structure keeps responsibilities clear: src/routes for route definitions, src/controllers for request and response handling, src/services for business logic, src/models for Mongoose schemas, src/middlewares for auth, validation and errors, src/config for environment and database setup, src/utils for helpers, and tests alongside or in a tests folder. Keep app.js, which builds the app, separate from server.js, which listens, so tests can import the app.
28

A for loop using var with setTimeout inside prints 3, 3, 3 instead of 0, 1, 2. Why, and how do you fix it?

Save to ▾
Show answer
var is function-scoped, so all three callbacks close over the same variable, which has become 3 by the time the timers fire. The simplest fix is to declare the loop variable with let, because let creates a fresh binding for every iteration. Older fixes include wrapping the body in an immediately invoked function or passing i as the third argument to setTimeout.
29

Write a reusable useFetch custom hook.

Save to ▾
Show answer
It returns data, error and loading state and aborts stale requests. function useFetch(url) { const [state, setState] = useState({ data: null, error: null, loading: true }); useEffect(() => { const controller = new AbortController(); setState((s) => ({ ...s, loading: true })); fetch(url, { signal: controller.signal }) .then((r) => { if (!r.ok) throw new Error(r.status); return r.json(); }) .then((data) => setState({ data, error: null, loading: false })) .catch((error) => { if (error.name !== 'AbortError') setState({ data: null, error, loading: false }); }); return () => controller.abort(); }, [url]); return state; }
30

The business wants total sales per category for the last 30 days. How would you build it in MongoDB?

Save to ▾
Show answer
Use an aggregation pipeline: $match orders with status paid and createdAt in the last 30 days, using an index on createdAt; $unwind the items array; $group by items.category summing items.price times items.qty; then $sort by total descending. If the report is viewed often, precompute daily totals into a summary collection with a scheduled job or $merge, so the dashboard reads small documents.
31

How would you use Redis caching in a MERN backend and what are the pitfalls?

Save to ▾
Show answer
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.
32

A MongoDB query on an orders collection takes 3 seconds. How do you diagnose and fix it?

Save to ▾
Show answer
Run the query with .explain('executionStats') and check whether the winning plan is COLLSCAN and how totalDocsExamined compares to nReturned. Create an index matching the filter and sort, following ESR, and confirm it becomes IXSCAN. Also project only needed fields, add limits, use lean in Mongoose, and check the profiler or Atlas Performance Advisor for other slow queries. Re-test with production-like data volume.
33

Write an asyncHandler wrapper for Express 4 route handlers.

Save to ▾
Show answer
It catches rejected Promises and forwards them to error middleware. const asyncHandler = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); router.get('/:id', asyncHandler(async (req, res) => { const user = await User.findById(req.params.id); if (!user) return res.status(404).json({ message: 'Not found' }); res.json(user); })); Express 5 does this automatically, but many existing codebases still use this pattern.
34

When should you use useReducer instead of useState?

Save to ▾
Show answer
Use useReducer when state has multiple related fields, when the next state depends on complex logic, or when many event handlers update state in different ways. A reducer is a pure function (state, action) => newState that centralises transitions and is easy to unit test, for example a cart with add, remove, change quantity and clear actions. For simple independent values, useState is clearer.
35

Props are being passed through five levels of components that do not use them. How would you refactor?

Save to ▾
Show answer
This is prop drilling. First try component composition: pass ready-made elements as children or props so intermediate components do not need the data. If many distant components need it, create a Context with a custom hook like useAuth. For complex or frequently updated shared state, use a store such as Zustand or Redux Toolkit with selectors so only interested components re-render.
36

Show the use of $push, $addToSet, $inc and $pull update operators.

Save to ▾
Show answer
Update operators change parts of a document atomically: db.posts.updateOne({ _id: id }, { $inc: { views: 1 } }) db.posts.updateOne({ _id: id }, { $addToSet: { tags: 'mongodb' } }) db.posts.updateOne({ _id: id }, { $push: { comments: { text: 'Nice', at: new Date() } } }) db.posts.updateOne({ _id: id }, { $pull: { tags: 'old' } }) $addToSet avoids duplicates, while $push always appends. Add $slice inside $push to cap an array's length.
37

Describe a mistake you made with data and how you handled it.

Save to ▾
Show answer
Situation: I ran an update script against the staging database with a wrong filter and modified thousands of records. Task: restore data before QA testing next morning. Action: I informed my lead immediately, restored from the nightly backup, re-applied the day's valid changes, and then added a dry-run mode and a count confirmation step to our scripts. Result: QA was not blocked, and no similar incident happened again.
38

Write a production Dockerfile for a Node.js Express API.

Save to ▾
Show answer
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 is PM2 and why is it used to run Node.js in production?

Save to ▾
Show answer
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.
40

Explain the core ideas of Redux Toolkit.

Save to ▾
Show answer
Redux keeps global state in a single store that changes only through dispatched actions handled by reducers. Redux Toolkit is the official modern way to write Redux: configureStore sets up the store with DevTools, createSlice generates actions and reducers and lets you write mutating code safely using Immer, and createAsyncThunk handles async requests. RTK Query adds data fetching and caching. Components use useSelector and useDispatch.

Frequently asked questions

What does a Full Stack JavaScript Developer do?

A Full Stack JavaScript Developer with two to five years of experience owns features end to end and makes design decisions on both sides. You plan data models, API contracts and frontend state together, review code, write tests and handle deployments. Companies expect you to balance speed with quality, debug across layers, and support juniors while delivering modules independently and on schedule.

Which skills are tested in a Full Stack JavaScript Developer interview?

Expect questions on Feature ownership, API design, React performance, Automated testing, CI/CD. Most rounds also ask you to explain a project and solve one practical problem live.

How do I prepare for a Full Stack JavaScript Developer interview?

Revise React Hooks, State and Performance, Express.js and REST APIs, MongoDB and Mongoose, Testing, Deployment and DevOps first using the topic sheets, practise the questions on this page aloud, then do one full mock interview to practise timing.