Interview questions · free

Full Stack Developer interview questions and answers

37 questions Full Stack Developer interviews in India ask, grouped by the 9 skills they test, with a short model answer for each. Then the HR round every job has. Try each one out loud before you open the answer.

  • 37 questions
  • 9 skills
  • 19 for freshers
  • Updated 30 Oct 2026

First mock interview free: 3 questions, a score and feedback on each · No card needed

Answer out loud first. Read the question, say your answer as you would in the room, then open the model answer and compare. Interviewers ask follow-ups, so learn the reasoning, not the words.

JavaScript · Core skill

Core language

A full stack developer writes JavaScript on both the browser and the server, so interviewers test the language itself before asking about any framework.

What does this print, and why: for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); }? How do you make it print 0, 1, 2?Fresher

It prints 3, 3, 3. var is function-scoped, so there's one i shared by the whole loop. The setTimeout callbacks run only after the loop has finished, when i is already 3, and each callback reads that same variable through its closure.

The simplest fix is let: let is block-scoped, and a for loop with let creates a new binding of i for every iteration, so each callback closes over its own value and it prints 0, 1, 2. Before let existed, people wrapped the body in a function called immediately with i as an argument. The question tests closures, scope and the event loop together, so mention all three.

What is the difference between a shallow copy and a deep copy of an object? How do you make each?Fresher

A shallow copy creates a new top-level object but shares nested objects with the original: { ...user } or Object.assign({}, user). Changing the copy's address.city changes the original's too. A deep copy duplicates every level, so the two are completely independent.

For a deep copy, structuredClone(obj) is the modern built-in way and handles dates, maps and circular references, though not functions. JSON.parse(JSON.stringify(obj)) is an older trick that turns dates into strings and drops undefined values and functions. This matters in React, where you update state by copying only the parts you change: { ...user, address: { ...user.address, city } }. Mutating nested state directly leaves the UI out of date.

Explain prototypal inheritance. How does it relate to the class keyword?1-6 years

Every JavaScript object has an internal link to another object, its prototype. When you read a property the object doesn't have, JavaScript looks for it up the prototype chain until it finds it or reaches null. That's how arrays get map and push: they come from Array.prototype, shared by all arrays rather than copied into each one.

The class keyword is mostly cleaner syntax over this. Methods defined in a class go on its prototype, and extends links the subclass's prototype to the parent's. Object.create(proto) makes an object with a chosen prototype directly. Mention why it matters: prototype methods are shared, which saves memory, and Object.hasOwn tells an object's own properties from inherited ones.

Your React frontend uses import and export, but your Node backend uses require. What's the difference, and what problems have you seen when mixing them?1-6 years

Those are the two module systems. CommonJS (require and module.exports) was Node's original system: modules load synchronously at runtime, and you can require conditionally. ES modules (import and export) are the JavaScript standard: imports are static, so tools can analyse them and drop unused code (tree shaking). The frontend uses them through a bundler like Vite; in Node, a package with "type": "module" in package.json, or .mjs files, uses them.

Common problems: requiring a package that ships only ES modules fails in older Node versions, default and named exports get confused between the two, and __dirname doesn't exist in ES modules (use import.meta.url). Choosing ES modules on both sides of a new project avoids most of this.

UI framework · Core skill

Components and props

React is the most common frontend in full stack openings, and interviewers want to see that you can connect its components cleanly to your own API.

What are the ways to render something conditionally in React? What's the bug in {items.length && <List items={items} />}?Fresher

Use an if statement with an early return for whole-component cases, such as returning a spinner while loading; the ternary condition ? a : b to choose between two elements; and condition && element to show something or nothing. Returning null renders nothing.

The bug: when items is empty, items.length is 0, and && returns that 0, which React renders as the text "0" on the page. false, null and undefined render nothing, but numbers do. Fix it with items.length > 0 && followed by the element, or a ternary that returns null. For more than two cases, an object that maps a status to a component reads better than nested ternaries.

How does a child component send data back to its parent in React?Fresher

Data flows down through props, so the child can't change the parent's state directly. Instead, the parent passes a function down as a prop and the child calls it with the data. For example, a ProductPage keeps the cart in state and passes onAdd={(item) => setCart([...cart, item])} to each ProductCard; when its button is clicked, the card calls onAdd(product).

If two siblings need the same data, move the state up to their closest common parent (lifting state up) and pass it down to both. When that means passing props through many levels that don't use them, use React Context or a state library instead. Saying "data down, events up" sums it up well.

How do you load data from your Express API into a React component? What states and problems do you handle?1-6 years

A simple version uses useEffect: start the request when the component mounts or the id changes, and keep the data, a loading flag and an error in state, so the UI shows a spinner, the data, or an error with a retry button. Check response.ok, since fetch doesn't reject on a 404 or 500. Use an AbortController in the effect's cleanup, so a slow response for an old id can't overwrite the new one.

In real projects I'd use a data library such as TanStack Query or SWR, which adds caching, deduplication, retries and refetching. Also mention that in development React's Strict Mode runs effects twice, which helps reveal missing cleanups.

A table of 2,000 rows re-renders slowly every time one row's checkbox changes. How would you make it faster?1-6 years

First confirm where the time goes with the React DevTools Profiler. Usually every row re-renders because the parent's state changed. Wrap the row component in React.memo so it re-renders only when its own props change, and keep those props stable: pass the row's data and a callback wrapped in useCallback, not a new inline function or object on every render. Make sure the keys are stable ids.

If it's still slow, the real problem is 2,000 DOM rows: virtualise the list with a library such as react-window or TanStack Virtual, so only the visible rows are rendered, or paginate on the server, which your API can support with limit and cursor parameters. Measure again after each change.

Node.js · Core skill

Express and REST APIs

Express is the usual backend in JavaScript full stack roles, and interviewers check that you can design an API the React side can rely on.

What is middleware in Express? Give examples from a project.Fresher

Middleware is a function that receives the request, the response and next, and runs in the order it was added. It can read or change the request, end the response, or call next() to pass control on; if it does neither, the request hangs.

Typical examples: express.json() parses JSON bodies into req.body; cors() adds headers so the React app's origin may call the API; a logger such as morgan records each request; an auth middleware checks the token and sets req.user or returns 401; and an error handler at the end turns errors into JSON responses. Order matters: express.json() must run before routes that read req.body, and the error handler goes last.

Design the REST API for a simple blog with posts and comments.Fresher

Name resources with plural nouns and let HTTP methods say the action: GET /posts lists posts (with ?page= and ?author= for filtering), GET /posts/:id gets one, POST /posts creates one, PATCH /posts/:id updates part of it and DELETE /posts/:id removes it. Comments belong to a post, so GET /posts/:id/comments and POST /posts/:id/comments.

Return the right status codes: 201 Created with the new post after a POST, 204 No Content after a delete, 400 for invalid input, 401 when not logged in, 403 when editing someone else's post, and 404 when it doesn't exist. Avoid verbs in URLs like /getPosts. Send errors in one consistent JSON shape, so the frontend can display them the same way everywhere.

Your React form already validates the input. Why validate again in Express, and how would you do it?1-6 years

Frontend validation is only for the user's convenience: anyone can call the API directly with Postman or curl, or change the JavaScript in their browser. So the server must check everything it receives: types, required fields, lengths, formats and allowed values, plus business rules like a booking date not being in the past.

I'd use a schema library such as Zod, Joi or express-validator, in a middleware before the route handler, and return 400 with field-level errors, for example { errors: { email: 'Enter a valid email' } }, so the React form can show each message next to its field. Strip unknown fields too, so a user can't slip in isAdmin: true. With Zod, the same schema can be shared with the frontend.

A list API returns 50,000 orders and the React page freezes. How would you design pagination?1-6 years

Never return everything. Offset pagination, GET /orders?page=3&limit=20 using LIMIT and OFFSET in SQL, is simple and lets users jump to a page, and returning a total count lets the UI show page numbers. But large offsets get slow, because the database still walks past all the skipped rows, and rows shift if new orders arrive while someone is paging.

Cursor (keyset) pagination fixes both: the client sends the last item's id, and the query fetches the rows after it (WHERE id < :cursor ORDER BY id DESC LIMIT 20) using an index. It suits infinite scroll. Either way, cap the limit on the server, sort by an indexed column, and return the next cursor or page in the response.

CS fundamentals · Core skill

DBMS and SQL

Full stack developers design their own tables and write their own queries, so interviewers check SQL, normalisation and what happens when two users change data at once.

What is normalisation? Explain 1NF, 2NF and 3NF with an example.Fresher

Normalisation organises tables to remove duplicated data, so each fact is stored once and updates can't leave copies that disagree. 1NF: each column holds a single value, so no comma-separated phone numbers in one cell; repeated values go into rows of their own. 2NF: in a table with a composite key, every column depends on the whole key. In order_items, keyed by order_id and product_id, product_name depends only on product_id, so it belongs in products. 3NF: no column depends on another non-key column. If orders stores customer_id and also customer_email, the email depends on the customer, not the order, so it belongs in customers.

Mention that read-heavy systems sometimes denormalise on purpose for speed.

Write a query to list customers who have placed more than three orders. What is the difference between WHERE and HAVING?Fresher

SELECT c.id, c.name, COUNT(o.id) AS order_count FROM customers c JOIN orders o ON o.customer_id = c.id GROUP BY c.id, c.name HAVING COUNT(o.id) > 3 ORDER BY order_count DESC;

WHERE filters rows before they are grouped, so it can't use aggregate functions like COUNT. HAVING filters groups after GROUP BY, so conditions on totals go there. To count only orders after a certain date, put the date condition in WHERE and the count condition in HAVING. Filtering in WHERE whenever you can is also faster, because fewer rows reach the grouping step.

What are dirty reads, non-repeatable reads and phantom reads? Which isolation levels prevent them?1-6 years

A dirty read is reading another transaction's change before it commits; if it rolls back, you've read data that never existed. A non-repeatable read is reading the same row twice in one transaction and getting different values, because someone committed an update in between. A phantom read is running the same query twice and seeing new rows another transaction inserted.

Read Uncommitted allows all three. Read Committed prevents dirty reads and is PostgreSQL's default. Repeatable Read also prevents non-repeatable reads and is MySQL InnoDB's default; PostgreSQL's Repeatable Read prevents phantoms as well. Serializable prevents all of them, at the cost of more locking or retried transactions. Higher isolation is safer but slower, so choose it per transaction.

Two users try to book the last seat for a show at the same moment. How do you make sure only one succeeds?1-6 years

Reading the count, checking it in Node and then updating is a race: both requests can read "one seat left" before either writes. Let the database decide. The simplest way is a conditional update: UPDATE shows SET seats_left = seats_left - 1 WHERE id = ? AND seats_left > 0, then check the affected row count; zero means the seat has gone, so tell the user. When booking specific seats, a unique constraint on (show_id, seat_no) in the bookings table makes the second insert fail.

If you need several steps, use a transaction with SELECT ... FOR UPDATE to lock the row until you commit. Whatever you choose, test it by firing parallel requests, not by clicking twice.

Reading an answer isn't the same as giving one

In a mock interview you answer new Full Stack Developer questions out loud or typed, and every answer is scored, with what to fix and a stronger answer.

Try it free

Web platform

HTML and CSS

Even with a component library, a full stack developer has to fix layouts and build forms, so interviewers ask the CSS and HTML questions that come up daily.

Explain CSS position: static, relative, absolute, fixed and sticky.Fresher

static is the default: the element sits in the normal flow, and top or left have no effect. relative keeps its place in the flow but can be nudged with top and left, and it becomes the reference for absolutely positioned children. absolute takes the element out of the flow and positions it against the nearest positioned ancestor, which is why a dropdown inside a relative container lines up with it. fixed positions against the viewport and stays put while scrolling, as for a chat button. sticky acts like relative until scrolling reaches a threshold such as top: 0, then sticks within its parent, as for table headers.

Also mention that z-index needs a positioned element (or a flex or grid item).

What would you put in the HTML of a login form so it works well for users?Fresher

Wrap the fields in a form element so Enter submits it, and give each input a label linked by for and id, so tapping the label focuses the field and screen readers announce it. Use the right types: type="email" shows the email keyboard on phones, and type="password" hides the text. Add autocomplete="email" and autocomplete="current-password" so password managers can fill them, required on mandatory fields, and a button with type="submit".

Show errors next to the field, in words, not only as a red border. And remember that HTML validation is only for convenience: the Express API must validate everything again, because anyone can skip the form.

Your CSS rule isn't being applied to an element. How do you find out why?1-6 years

Inspect the element in DevTools: the Styles panel shows every rule that matches, with overridden properties struck through, and the Computed tab shows the final value and which rule set it. If your rule doesn't appear at all, the selector doesn't match, the file isn't loaded, or there's a syntax error above it.

If it's struck through, another rule wins. The cascade decides: !important declarations beat normal ones, then specificity (inline styles, then IDs, then classes, attributes and pseudo-classes, then element names), and with equal specificity the later rule wins. Fix it by matching the winning rule's specificity or reorganising the CSS, not by adding !important everywhere. CSS modules or cascade layers help avoid these fights.

Node.js

Authentication

Login touches both halves of the stack, so full stack interviews ask how authentication works end to end, from the React screen to the Express route.

What is the difference between session-based and JWT-based authentication?Fresher

With sessions, after login the server stores a session record (in memory, a database or Redis) and sends the browser a cookie holding only a random session id. Each request sends the cookie, and the server looks up the session. Logging a user out or blocking them is easy: delete the session.

With JWT, the server signs a token containing the user's id and an expiry and gives it to the client; each request sends it, and the server checks the signature without a database lookup. That suits mobile apps and several services, but a JWT can't be cancelled before it expires without extra work, so keep it short-lived with a refresh token. For a typical web app with one backend, sessions in an HttpOnly cookie are simpler and safe.

How would you protect routes in both your React app and your Express API?1-6 years

In React, wrap private routes in a component that checks whether the user is logged in, using state loaded from an endpoint like GET /me, and redirects to the login page if not; also hide buttons the user's role can't use. This is only for a good experience: anyone can change the code in their browser.

The real protection is on the server. An auth middleware on every private route checks the session or token and returns 401 if it's missing or invalid. Then each handler checks authorisation: an admin route checks the role, and editing a post checks that it belongs to req.user, returning 403 or 404 otherwise. Forgetting that ownership check is one of the most common security bugs in APIs.

How does "Sign in with Google" work? What would you build on your side?1-6 years

It uses OAuth 2.0 with OpenID Connect, usually the authorisation code flow. Your app redirects the user to Google with your client id, the scopes (openid, email, profile), a redirect URL and a random state value. The user signs in and agrees, and Google redirects back with a short-lived code. Your server, never the browser, exchanges the code and your client secret for tokens, verifies the ID token's signature, audience and expiry, and reads the user's Google id and email.

Then find or create the user by that Google id and start your own session. Check that state matches to prevent CSRF, and use PKCE. Libraries such as Passport.js handle much of this.

System design

Data modelling and storage

Full stack developers often choose the database and design the schema themselves, so interviewers ask how you model data and what you'd do as it grows.

For a new full stack app, how would you choose between PostgreSQL and MongoDB?Fresher

Start from the data and how it will be used. A relational database such as PostgreSQL or MySQL fits data with clear relationships, like users, orders, payments and products, where you need joins, constraints and transactions that keep money and stock correct. A document database such as MongoDB fits data that is read and written as a whole and whose shape varies, like product catalogues with different attributes per category, content, or event logs.

For most business apps a relational database is the safer default, and PostgreSQL can store JSON columns for the flexible parts. Say you'd choose by the access patterns and the team's experience, not by fashion, and that many systems use both.

Design the main tables for an online shop: users, products and orders.Fresher

users (id, name, email unique, phone, created_at); products (id, name, price, stock, category_id); orders (id, user_id, status, total, delivery_address, created_at); and order_items (order_id, product_id, quantity, unit_price), because one order has many products and one product appears in many orders, a many-to-many relationship that needs a table in between.

The important detail is unit_price in order_items: copy the price at the time of purchase, because the product's price will change later and old invoices must not. For the same reason, store the delivery address on the order, not only on the user. Add indexes on foreign keys like orders.user_id and on columns you filter by, such as orders.status.

What is the CAP theorem? What does it mean for a real application?1-6 years

CAP says that when a network partition happens, meaning the servers of a distributed database can't reach each other, the system must choose between consistency (every read sees the latest write) and availability (every request gets an answer, possibly with old data). Partitions can't be ruled out across machines, so the real choice is what to give up while one lasts.

It depends on the data. A bank balance or a seat booking should prefer consistency: better an error than selling the same seat twice. A like count or product reviews can prefer availability and catch up later (eventual consistency). Many databases let you choose per operation, such as MongoDB's read and write concerns. Mention that in normal operation the trade-off is latency against consistency.

Your orders table has grown to hundreds of millions of rows and queries are slowing down. What would you do?1-6 years

First find which queries are slow and why, using the slow query log and EXPLAIN, and fix those: add or adjust composite indexes, avoid SELECT *, and stop queries that scan the whole table. Then reduce the data each query searches: archive old orders to a separate table or cheaper storage, and use table partitioning by date, which PostgreSQL and MySQL both support, so a query for recent orders reads only recent partitions.

For read load, add read replicas and send reports to them, and cache hot data such as a user's latest orders. Sharding, splitting rows across several database servers by a key like user_id, comes last, because it makes joins, transactions and operations much harder.

Cloud

Cloud platforms and containers

Full stack developers are often expected to deploy what they build, so interviewers ask which cloud services you'd use for the frontend, the API, the database and files.

What are the ways to deploy a full stack app (React frontend, Node API, database) on a cloud like AWS?Fresher

The React build is just static files, so the simplest home is object storage with a CDN in front, such as S3 with CloudFront, or a static hosting service. For the API there are several levels. A virtual machine (EC2) gives full control, but you patch and scale it yourself. A platform service (Elastic Beanstalk, Azure App Service, Render) runs your code and manages the servers. Containers (ECS, or Kubernetes with EKS) package the app with its dependencies so it runs the same everywhere. Serverless functions (Lambda) run per request and cost nothing when idle.

The database usually goes on a managed service such as RDS. For a small project, a platform service plus a managed database is the quickest start.

Why would you use a managed database such as Amazon RDS instead of installing MySQL on your own server?Fresher

A managed database takes over the operational work: automatic backups with point-in-time recovery, operating system and database patching, monitoring, a standby copy in another availability zone that takes over if the main one fails, read replicas in a few clicks, and easy storage growth. Doing all of that well yourself takes real time and experience, and one mistake with backups can lose data.

The trade-offs are cost, since you pay more than for a bare server, and less control: you can't log in to the operating system or install every extension. For most teams the managed option is worth it. Add that you'd still test restoring a backup rather than assume it works.

Users upload profile photos and documents. Where would you store them, and how would the upload work?1-6 years

Not on the API server's disk: servers and containers get replaced or run as several copies, and a file on one wouldn't be on the others. Store files in object storage such as S3, and keep only each file's key and metadata in the database.

For the upload, the API checks the user may upload and creates a short-lived pre-signed URL; the browser uploads straight to S3 with it, so large files never pass through Node. Keep the bucket private and serve files through pre-signed download URLs or a CDN. Limit file size and type, and scan documents if needed. On cost, storage is cheap but data transferred out to the internet is charged, so a CDN and resized images help.

CI/CD

Pipelines

Teams expect full stack developers to keep the pipeline green for both the frontend and the backend, so interviewers ask how builds, tests, deploys and secrets fit together.

What is CI/CD? What stages would a pipeline for a web app have?Fresher

Continuous integration means every push or pull request is built and tested automatically, so problems show up within minutes, not at release time. Continuous delivery goes further: every change that passes can be released with one step, and continuous deployment releases it automatically.

A typical pipeline: check out the code, install dependencies with npm ci (which installs exactly what the lock file says), run the linter and type checks, run unit tests, build the frontend and backend, perhaps run integration or end-to-end tests, then deploy to staging and, after approval, to production. If any stage fails, the pipeline stops and the team is told. The result is small, frequent, low-risk releases.

Walk me through a GitHub Actions workflow you'd write for a repository with a React frontend and an Express backend.1-6 years

A YAML file in .github/workflows runs on pull requests and on pushes to main. A test job uses actions/checkout and actions/setup-node with npm caching, runs npm ci, the linter and the tests for the backend, and the same plus npm run build for the frontend; a matrix or two separate jobs can run both sides in parallel. The build output is uploaded as an artifact, so the deploy uses exactly what was tested.

A deploy job runs only on main and only after the tests pass (needs: test), uses a protected environment with a required approval for production, and reads its credentials from GitHub secrets. Caching dependencies saves minutes per run, and testing every pull request keeps main releasable.

How do you handle secrets like database passwords and API keys, in the pipeline and in a full stack app?1-6 years

Never commit them: keep .env out of git, and use a secret scanner to catch mistakes. In the pipeline, store them as GitHub Actions secrets or in your CI tool's credential store; they're masked in logs, and environment secrets with approval rules keep production keys away from other branches. For cloud access, prefer OIDC federation, where the pipeline gets short-lived credentials, over long-lived access keys. On the server, read them from environment variables or a secrets manager.

A key full stack point: anything in the frontend build, such as VITE_ variables, is visible to every user in the browser. Only public keys belong there; secret keys stay on the server. If a secret leaks, rotate it at once.

Every job

HR and behavioural round

Full stack developers often own features from screen to database, so the HR round looks for ownership, honest self-assessment and how you juggle work across both sides.

Tell me about yourself.Fresher

Keep it to a minute and show both sides through one project. For example: "I'm a [degree] graduate from [college], and I enjoy building complete products, from the screen to the database. My main project is [project], a [what it does] with a React frontend, a Node and Express API and PostgreSQL, deployed on [platform]. I built [a feature end to end, such as login and payments], and [result: it's used by 200 students at my college]. I'm looking for a full stack role where I can own features end to end and grow deeper on the backend."

Have the live link and the code ready to show.

Do you prefer frontend or backend? Why do you call yourself full stack?Fresher

Be honest: few people are equally strong at both, and interviewers know it. Name your stronger side and show you can deliver on the other. For example: "I'm stronger on the backend; API design and databases come more naturally to me. But I can build a complete feature on my own, including the React screens: in [project] I built [feature] on both sides. For me, full stack means understanding the whole path of a request, so I can fix a problem wherever it is."

Don't claim to be an expert at everything; the next technical question will test it.

Tell me about the project you're proudest of.Fresher

Pick one with real decisions in it and tell it as a story: the problem, your role, the hard part, the result. For example: "In my final year I built [project] to [problem it solved]. I designed the database and the API and built most of the React app. The hardest part was [for example, stopping two students from booking the same lab slot], which I solved with [a unique constraint and a transaction]. [Number] people used it during [event], and I learned [lesson]."

Expect follow-up questions on every technology you mention, so name only what you can explain.

You have an urgent frontend bug, a backend task due today and a teammate asking for help. How do you prioritise?1-6 years

Show that you judge by impact and communicate, rather than silently juggling. A structure: assess the impact, decide, tell people. For example: "I'd first check how many users the bug affects. If it's blocking payments, it comes first, and I'd tell my lead the backend task may slip, with a new time. If it's minor, I'd log it, finish the task due today, and give my teammate a time when I can help, or point them to someone who can. Recently [a similar call you made and how it turned out]."

The key point: no one should be surprised by a missed deadline.

Tell me about a mistake you made that affected production.1-6 years

Choose a real mistake, own it plainly, and focus on the recovery and what you changed. For example: "I deployed a database migration that renamed a column while the old version of the API was still running, so some requests failed for about ten minutes (situation and task). I put the old column name back with a quick migration, told my lead, and wrote a short note on what happened (action). Since then I make schema changes in two steps, adding the new column first and removing the old one in a later release, and our release checklist includes it (result)."

Interviewers look for honesty and learning, not a perfect record.

Free interview questions, roadmaps and mock interviews: https://myskillgrid.com/interview-questions/full-stack-developer/

Ready to answer them for real?

Your first Full Stack Developer mock interview is free: 3 questions, a score and feedback for each, and a stronger answer to learn from, in about 10 minutes.