Top 60 Full Stack Web Development Interview Questions and Answers (2025)

Preparing for a Full Stack Web Developer interview?
This guide covers the top 60 most asked questions with expert answers.
It includes key topics like JavaScript, React, Node.js, Express.js, MongoDB, and Redux.
Interviewers test core concepts, problem-solving, and best practices.
Understanding these questions will boost your confidence.
You will learn about frontend, backend, database handling, and state management.
This blog helps freshers and experienced developers prepare efficiently.
Each question is explained with clear examples and practical use cases.
Mastering these concepts will help you stand out in technical interviews.
Start reading and enhance your Full Stack Web Development skills today!
Table of Contents
ToggleJavaScript & ECMAScript Interview Questions
- What are the key differences between var, let, and const?
Answer:
- var: Function-scoped, can be redeclared and updated, hoisted with undefined.
- let: Block-scoped, can be updated but not redeclared, hoisted but not initialized.
- const: Block-scoped, cannot be updated or redeclared, must be initialized.
- What is event delegation in JavaScript?
Answer: Event delegation is a technique where a parent element handles events for dynamically added child elements using event bubbling.
Example –
document.getElementById(“parent”).addEventListener(“click”, function (e) {
if (e.target && e.target.matches(“button”)) {
console.log(“Button clicked:”, e.target.innerText);
}
});
This improves performance as we attach a single event listener instead of multiple ones.
- What is the difference between == and === in JavaScript?
Answer:
- == (Abstract Equality): Compares values with type coercion.
console.log(5 == “5”); // true
- === (Strict Equality): Compares both value & type.
console.log(5 === “5”); // false
- What are Promises and how do they work in JavaScript?
Answer: A Promise is an object that represents the eventual completion (or failure) of an asynchronous operation.
Example-
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => resolve(“Data received!”), 2000);
});
fetchData.then(data => console.log(data)).catch(error => console.error(error));
Promise object has following three states:
- Pending → Initial state.
- Fulfilled → When resolved.
- Rejected → When an error occurs.
- What are ES6 modules and how do they work?
Answer: ES6 introduced modules to structure JavaScript code.
- Exporting a module:
export const greet = () => console.log(“Hello!”);
- Importing a module:
import { greet } from ‘./module.js’;
greet();
Modules allow better code organization and avoid global scope pollution.
- What is the difference between synchronous and asynchronous JavaScript?
Answer:
- Synchronous: Executes code line by line, blocking further execution until the current task completes.
- Asynchronous: Uses callbacks, promises, or async/await to handle operations without blocking execution.
Example-
console.log(“Start”);
setTimeout(() => console.log(“Async Task”), 1000);
console.log(“End”);
Output-
Start
End
Async Task (after 1 second)
- What are higher-order functions in JavaScript?
Answer: A higher-order function is a function that takes another function as an argument or returns a function.
Example-
function greet(name) {
return function (message) {
console.log(`${message}, ${name}!`);
};
}
const greetUser = greet(“Tushar”);
greetUser(“Hello”); // Output: Hello, Tushar!
- What is the purpose of ‘this’ keyword in JavaScript?
Answer: The ‘this’ keyword refers to the object it belongs to. Its value depends on how a function is invoked.
Example-
const person = {
name: “Tushar”,
greet: function() {
console.log(`Hello, ${this.name}`);
}
};
person.greet(); // “Hello, Tushar”
In arrow functions, this is lexically bound (inherits from the parent scope).
- What are closures in JavaScript?
Answer: A closure is a function that remembers variables from its outer scope even after the outer function has executed.
Example-
function counter() {
let count = 0;
return function () {
return ++count;
};
}
const increment = counter();
console.log(increment()); // 1
console.log(increment()); // 2
- What is the difference between call(), apply(), and bind() in JavaScript?
Answer:
Method | Description |
call() | Calls a function with a given this value and arguments passed separately. |
apply() | Calls a function with a given this value and arguments passed as an array. |
bind() | Returns a new function with a bound this value. |
Example-
function greet(city) {
console.log(`Hello ${this.name} from ${city}`);
}
const user = { name: “Garima” };
greet.call(user, “New Delhi”);
greet.apply(user, [“Noida”]);
const boundGreet = greet.bind(user, “Ghaziabad”);
boundGreet();
- What is debouncing and throttling in JavaScript?
Answer: Both are performance optimization techniques for handling frequent function calls.
Debouncing : Ensures a function executes only after a specified delay (useful for input search).
Example-
function debounce(fn, delay) {
let timer;
return function (…args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
}; }
const search = debounce(() => console.log(“Search API Call”), 500);
Throttling : Ensures a function executes at most once in a given time period (useful for scroll events).
Example-
function throttle(fn, limit) {
let lastCall = 0;
return function (…args) {
const now = Date.now();
if (now – lastCall >= limit) {
lastCall = now;
fn.apply(this, args);
}
};
}
const handleScroll = throttle(() => console.log(“Scrolled!”), 1000);
- What is the difference between shallow copy and deep copy in JavaScript?
Answer:
Type | Description |
Shallow Copy | Copies references but not nested objects. |
Deep Copy | Creates a completely new instance of an object, including nested objects. |
Shallow Copy Example-
const obj1 = { name: “Tushar”, details: { age: 30 } };
const obj2 = { …obj1 };
obj2.details.age = 40;
console.log(obj1.details.age); // 40 (both objects share the same reference)
Deep Copy Example-
const obj1 = { name: “Garima”, details: { age: 30 } };
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.details.age = 40;
console.log(obj1.details.age); // 30 (objects are independent)
- What are JavaScript prototypes and how do they work?
Answer: JavaScript uses prototypal inheritance, meaning objects inherit properties and methods from a prototype.
Example of Prototype Inheritance-
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const user = new Person(“Garima”);
user.greet(); // “Hello, my name is Garima”
In above code snippet, user inherits greet() from Person.prototype.
- What is the difference between setTimeout() and setInterval()?
Answer:
Function | Purpose |
setTimeout(fn, delay) | Executes once after a delay. |
setInterval(fn, delay) | Executes repeatedly at fixed intervals. |
Example of setTimeout-
setTimeout(() => console.log(“Executed after 2 seconds”), 2000);
Example of setInterval-
const interval = setInterval(() => console.log(“Repeating every 1 second”), 1000);
// Stop after 5 seconds
setTimeout(() => clearInterval(interval), 5000);
- What are JavaScript generators and how do they work?
Answer: Generators (function*) are special functions that can pause and resume execution.
Example-
function* generatorExample() {
yield “First”;
yield “Second”;
return “Finished”;
}
const gen = generatorExample();
console.log(gen.next()); // { value: “First”, done: false }
console.log(gen.next()); // { value: “Second”, done: false }
console.log(gen.next()); // { value: “Finished”, done: true }
Use Case: Generators are useful for handling asynchronous operations in an iterative manner.
React.js Interview Questions
- What is the Virtual DOM in React?
Answer: The Virtual DOM (VDOM) is a lightweight copy of the actual DOM. React updates this VDOM first and then applies the efficient diffing algorithm to update only the changed parts in the real DOM, improving performance.
- What is reconciliation in React?
Answer: Reconciliation is the process React uses to update the DOM efficiently by comparing the Virtual DOM with the previous state and updating only the changed elements.
- What is the difference between functional and class components in React?
Answer:
- Functional Components:
- Stateless (before hooks), simpler, performance-friendly.
- Uses hooks like useState, useEffect.
- Functional Components:
Example-
const Welcome = () => <h1>Hello, React!</h1>;
- Class Components:
- Uses this.state and lifecycle methods.
- Class Components:
Example-
class Welcome extends React.Component {
render() {
return <h1>Hello, React!</h1>;
}
}
React hooks have made functional components more powerful, reducing the need for class components.
- What are controlled and uncontrolled components in React?
Answer:
- Controlled Component: Manages its state via useState.
- Uncontrolled Component: Uses useRef to access DOM values.
Example-
// Controlled
<input value={value} onChange={(e) => setValue(e.target.value)} />
// Uncontrolled
<input ref={inputRef} />
- How do you optimize performance in a React application?
Answer:
- Use useMemo() for expensive calculations.
- Use useCallback() to prevent function re-creation.
- Lazy load components using React.lazy().
- Use React.memo to avoid unnecessary re-renders.
- What are React Hooks? Name some important hooks.
Answer: React Hooks allow functional components to manage state and lifecycle features without using class components.
Some important hooks are listed below-
- useState → Manages state.
- useEffect → Side effects (API calls, event listeners).
- useContext → Global state management.
- useReducer → Alternative to useState for complex state logic.
- useRef → Manipulates DOM elements directly.
- useMemo → Performance optimization.
- What is the purpose of useEffect in React?
Answer: useEffect is a React Hook used for handling side effects in functional components, such as:
- Fetching data from an API.
- Subscribing to events.
- Manipulating the DOM.
- Setting timers.
Example: Fetching API Data with useEffect
import { useState, useEffect } from ‘react’;
const FetchData = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetch(“https://jsonplaceholder.typicode.com/posts”)
.then(response => response.json())
.then(json => setData(json));
}, []); // Runs only once when the component mounts
return ( <div> {data.map(post => <p key={post.id}>{post.title}</p>)}
</div>
);};
Key Points:
- The empty dependency array [] ensures the effect runs only once (on mount).
- If dependencies are provided, it re-runs when dependencies change.
- What is the purpose of useRef in React?
Answer: useRef is used to Access DOM elements directly & Persist values without re-rendering.
Example-
import { useRef } from “react”;
function InputField() {
const inputRef = useRef(null);
return (
<div>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus Input</button>
</div>
);
}
- What is the difference between useState and useReducer?
Answer: Both are used for state management in React, but they have key differences:
Hook | When to Use | How it Works |
useState | Simple state logic | Directly updates state (setState) |
useReducer | Complex state logic (e.g., multiple state updates) | Uses a reducer function to handle state transitions |
useState Example-
import { useState } from “react”;
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
useReducer Example-
import { useReducer } from “react”;
const reducer = (state, action) => {
switch (action.type) {
case “increment”: return { count: state.count + 1 };
case “decrement”: return { count: state.count – 1 };
default: return state;
}};
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<button onClick={() => dispatch({ type: “increment” })}>+</button>
<button onClick={() => dispatch({ type: “decrement” })}>-</button>
<p>Count: {state.count}</p>
</div>
);
}
When to use useReducer?
- When managing multiple related states.
- When state transitions depend on previous states.
- What is React.memo and how does it work?
Answer: React.memo is a higher-order component (HOC) that prevents unnecessary re-renders of functional components by memorizing props.
Example-
Without React.memo (Unnecessary Re-Renders)
const Child = ({ name }) => {
console.log(“Child Rendered”);
return <p>Hello, {name}!</p>;
};
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<Child name=”Alice” />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Even though name remains unchanged, the Child component re-renders when the Parent state updates.
Example-
Optimized Version Using React.memo
const Child = React.memo(({ name }) => {
console.log(“Child Rendered”);
return <p>Hello, {name}!</p>;
});
Now, Child renders only when props change, reducing unnecessary re-renders.
- What is the difference between useEffect and useLayoutEffect?
Answer:
Hook | When it Runs | Use Case |
useEffect | After render & paint | Data fetching, API calls, subscriptions |
useLayoutEffect | Before the paint phase | DOM manipulations (e.g., measuring elements) |
Example of useEffect-
import { useEffect } from “react”;
useEffect(() => {
console.log(“Runs after render”);
}, []);
Example of useLayoutEffect-
import { useLayoutEffect, useRef } from “react”;
const ref = useRef();
useLayoutEffect(() => {
console.log(“Runs before the screen updates”);
ref.current.style.color = “red”;
}, []);
Use useLayoutEffect only when necessary, as it blocks painting.
- What are React Portals and why are they used?
Answer: React Portals allow rendering a child component outside the parent DOM hierarchy, useful for modals, tooltips, and popups.
Example: Using createPortal
- First, create a modal component
import { createPortal } from “react-dom”;
const Modal = ({ children }) => {
return createPortal(
<div className=”modal”>{children}</div>,
document.getElementById(“portal-root”) // Separate DOM node
);};
- Then, use the modal
function App() {
return (
<div>
<h1>App Component</h1>
<Modal>Modal Content Here</Modal>
</div>
);}
- Atlast, Ensure a separate root element in index.html
<div id=”portal-root”></div>
Note: Portals help avoid styling issues by rendering outside parent containers.
- What is React Router and why is it used?
Answer: React Router is a library for handling client-side navigation.
Example-
import { BrowserRouter, Route, Routes } from ‘react-router-dom’;
function App() {
return (
<BrowserRouter>
<Routes>
<Route path=”/” element={<Home />} />
<Route path=”/about” element={<About />} />
</Routes>
</BrowserRouter>
);
}
Note: It allows single-page applications (SPA) to navigate without page refresh.
- What are Suspense and Lazy Loading in React?
Answer: Suspense and Lazy Loading improve performance by loading components only when needed, reducing the initial bundle size.
Lazy Loading with React.lazy(): React.lazy() enables dynamic imports of components.
Example-
import React, { Suspense, lazy } from “react”;
const LazyComponent = lazy(() => import(“./HeavyComponent”));
function App() {
return (
<div>
<h1>My App</h1>
<Suspense fallback={<p>Loading…</p>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;
How It Works?
- React.lazy() dynamically imports the HeavyComponent only when required.
- Suspense wraps the lazy-loaded component and provides a fallback UI (Loading…) until the component loads.
When to Use Lazy Loading?
- Large components (e.g., dashboards, reports).
- Routes (React Router supports lazy-loaded routes).
- Third-party libraries.
- What is the difference between Context API and Redux?
Answer:
Feature | Context API | Redux |
Complexity | Simple | More complex |
Performance | May cause unnecessary re-renders | Optimized with reducers |
Use Case | Small-scale apps | Large-scale apps |
Redux Interview Questions
- What is Redux, and why do we use it in React?
Answer: Redux is a state management library used for maintaining a single source of truth in large applications. Redux is used for managing complex global states efficiently.
Key Concepts-
- Store: Centralized state.
- Actions: Objects describing events.
- Reducers: Pure functions updating state.
- Dispatch: Sends actions to the reducer.
Example-
const reducer = (state = { count: 0 }, action) => {
if (action.type === “INCREMENT”) return { count: state.count + 1 };
return state;
};
- What is the difference between Redux and Context API?
Answer:
Feature | Redux | Context API |
Complexity | More complex | Simpler |
Performance | Optimized with reducers | Can cause unnecessary re-renders |
Use Case | Large-scale applications | Small to medium applications |
Debugging | Supports time-travel debugging | Lacks debugging tools |
- What are Redux Middleware and why are they used?
Answer: Middleware in Redux enhances dispatching actions and is used for:
- Handling async actions (e.g., API calls).
- Logging, error tracking, and debugging.
Example: Middleware Logging Actions
const logger = (store) => (next) => (action) => {
console.log(“Dispatching:”, action);
let result = next(action);
console.log(“Next State:”, store.getState());
return result;
};
//Using Middleware in Redux Store
import { createStore, applyMiddleware } from “redux”;
const store = createStore(reducer, applyMiddleware(logger));
Common Redux Middleware:
- Redux Thunk – Handles async actions.
- Redux Saga – Uses generator functions for side effects.
- Logger Middleware – Logs dispatched actions.
- What is Redux Toolkit and how does it improve Redux?
Answer: Redux Toolkit (RTK) is the official, recommended way to write Redux logic. It simplifies Redux by:
- Reducing boilerplate code
- Providing built-in state immutability
- Optimizing performance
Example: Counter App using Redux Toolkit
import { createSlice, configureStore } from “@reduxjs/toolkit”;
// Slice (Reducers + Actions)
const counterSlice = createSlice({
name: “counter”,
initialState: { count: 0 },
reducers: {
increment: (state) => { state.count += 1; },
decrement: (state) => { state.count -= 1; }
}
});
// Store
const store = configureStore({ reducer: counterSlice.reducer });
// Exporting actions and store
export const { increment, decrement } = counterSlice.actions;
export default store;
Why Redux Toolkit?
- Eliminates manual reducer & action creation.
- Simplifies async logic with createAsyncThunk().
- Improves code readability and maintainability.
- How does useSelector and useDispatch work in React-Redux?
Answer: In React-Redux, useSelector and useDispatch are used for accessing and modifying the Redux store. Using useSelector + useDispatch eliminates the need for connect() HOC and Optimizes re-renders by selecting only required state properties.
Example: Using useSelector to Access State
import { useSelector } from “react-redux”;
function CounterDisplay() {
const count = useSelector((state) => state.count);
return <h1>Count: {count}</h1>;
}
Note: useSelector() fetches the state without re-rendering unnecessary components.
Example: Using useDispatch to Update State
import { useDispatch } from “react-redux”;
import { increment } from “./store”;
function CounterButton() {
const dispatch = useDispatch();
return <button onClick={() => dispatch(increment())}>Increment</button>;
}
Note: useDispatch() triggers actions without extra boilerplate.
Node.js & Express.js Interview Questions
- What is Node.js and why is it used?
Answer: Node.js is a JavaScript runtime built on Chrome’s V8 engine, allowing JS to run on the server. It is used for backend development, real-time applications, and APIs.
Node.js has following features:
- Asynchronous & Non-blocking.
- Single-threaded, event-driven.
- Scales well for I/O-heavy applications.
- What is an event loop in Node.js?
Answer: The event loop is a mechanism that allows Node.js to handle non-blocking I/O operations asynchronously.
Example-
console.log(“Start”);
setTimeout(() => console.log(“Inside setTimeout”), 0);
console.log(“End”);
Output-
Start
End
Inside setTimeout
- How does Node.js handle concurrency if it is single-threaded?
Answer: Node.js uses:
- Non-blocking I/O
- Event loop
- Worker threads for CPU-intensive tasks
- What is the difference between process.nextTick() and setImmediate()?
Answer:
- process.nextTick() → Executes before the next event loop iteration.
- setImmediate() → Executes in the next event loop cycle.
Example-
setImmediate(() => console.log(“setImmediate”));
process.nextTick(() => console.log(“nextTick”));
Output-
nextTick
setImmediate
- What is Middleware in Express.js?
Answer: Middleware functions in Express.js process requests before they reach route handlers.
Example-
app.use((req, res, next) => {
console.log(“Middleware executed!”);
next();
});
Types-
- Application-level
- Router-level
- Error-handling
- Built-in (like express.json())
- How do you handle errors in Express.js middleware?
Answer: Use a custom error-handling middleware.
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message });
});
- What is rate limiting in Express.js and how do you implement it?
Answer: Rate limiting restricts API calls per user/IP.
Example-
const rateLimit = require(‘express-rate-limit’);
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
app.use(limiter);
- What is the difference between req.query, req.params, and req.body in Express?
Answer:
- req.query → Extracts query params from URL (?name=John).
- req.params → Extracts route parameters (/users/:id).
- req.body → Extracts data from request body (POST, PUT).
Example-
app.get(‘/users/:id’, (req, res) => {
console.log(req.params.id); // URL Parameter
console.log(req.query.name); // Query Parameter
});
- What is the difference between blocking and non-blocking code in Node.js?
Answer: Node.js is non-blocking and asynchronous, meaning it does not wait for operations (like file reads) to complete before executing the next line of code. Non-blocking code improves performance and is preferred in Node.js.
Example: Blocking Code (Synchronous)
const fs = require(“fs”);
const data = fs.readFileSync(“file.txt”, “utf8”); // Blocks execution
console.log(data);
console.log(“This runs after file read.”);
Behaviour: Execution halts until the file is read.
Example: Non-Blocking Code (Asynchronous)
fs.readFile(“file.txt”, “utf8”, (err, data) => {
if (err) console.error(err);
else console.log(data);
});
console.log(“This runs first! (Non-blocking)”);
Behaviour: Execution continues without waiting.
- How do you secure Express.js applications?
Answer: Security in Express.js involves multiple best practices, such as:
- Use Helmet for Security Headers
const helmet = require(“helmet”);
app.use(helmet());
- Enable CORS Safely
const cors = require(“cors”);
app.use(cors({ origin: “https://example.com” })); // Restrict access
- Sanitize Input to Prevent NoSQL Injection & XSS
const mongoSanitize = require(“express-mongo-sanitize”);
app.use(mongoSanitize());
- Use Rate Limiting to Prevent Brute Force Attacks
const rateLimit = require(“express-rate-limit”);
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
app.use(limiter);
- Use HTTPS and Environment Variables
- Enable HTTPS in production.
- Store sensitive data in .env instead of hardcoding.
Note: Implementing these reduces security vulnerabilities significantly.
- What is CORS in Express.js, and how do you enable it?
Answer: CORS (Cross-Origin Resource Sharing) is a security mechanism that controls access to resources from different origins. By default, browsers restrict API calls from different origins due to the Same-Origin Policy. To enable CORS in Express.js, use the cors package.
Example-
const cors = require(‘cors’);
const express = require(‘express’);
const app = express();
app.use(cors()); // Enables CORS for all routes
app.get(‘/data’, (req, res) => {
res.json({ message: “CORS is enabled!” });
});
app.listen(3000, () => console.log(“Server running on port 3000”));
You can also restrict CORS to specific origins:
app.use(cors({ origin: ‘https://example.com’ })); // Allows only requests from
example.com
- How do you handle file uploads in Node.js with Express?
Answer: Use Multer, a middleware for handling file uploads.
Example-
Installation- npm install multer
Implementation
const express = require(“express”);
const multer = require(“multer”);
const upload = multer({ dest: “uploads/” }); // Destination folder
const app = express();
app.post(“/upload”, upload.single(“file”), (req, res) => {
res.send(`File uploaded: ${req.file.originalname}`);
});
app.listen(3000, () => console.log(“Server running on port 3000”));
Points to remember about Multer:
- Supports single file (upload.single()) and multiple file uploads (upload.array()).
- Stores files in the uploads/ directory.
- For advanced file handling, configure storage, size limits, and validation.
- What is the difference between app.use() and app.all() in Express.js?
Answer: app.use() attaches middleware globally or to a specific route while app.all() matches all HTTP methods (GET, POST, etc.) for a given route. Use app.use() for middlewares (like authentication) and app.all() for handling multiple HTTP methods.
Example of app.use()-
app.use((req, res, next) => {
console.log(“Middleware executed!”);
next();
});
Behaviour: Runs for all requests.
Example of app.all()-
app.all(“/dashboard”, (req, res) => {
res.send(“This runs for GET, POST, PUT, DELETE on /dashboard.”);
});
Behaviour: Runs only for /dashboard, but for all HTTP methods.
- How does clustering improve Node.js performance?
Answer: Since Node.js is single-threaded, it cannot use multiple CPU cores by default. Clustering solves this by running multiple instances of the application.
Example: Using the cluster Module
const cluster = require(“cluster”);
const os = require(“os”);
const express = require(“express”);
if (cluster.isMaster) {
const numCPUs = os.cpus().length;
console.log(`Master process started (PID: ${process.pid})`);
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else
{
const app = express();
app.get(“/”, (req, res) => res.send(`Handled by process ${process.pid}`));
app.listen(3000, () => console.log(`Worker started (PID: ${process.pid})`));
}
Benefits of Clustering
- Utilizes multiple CPU cores, improving performance.
- Handles more requests concurrently.
- Ensures high availability (if one worker crashes, others continue running).
Note: For large-scale apps, use clustering with PM2 process manager.
- What is authentication vs. authorization in web applications?
Answer: Authentication verifies who the user is (login process) while Authorization determines what the user is allowed to do.
Example in Node.js & Express (JWT Authentication)
- User logs in → Receives a JWT token.
- Token is sent with each request for protected routes.
- Server verifies the token → Grants or denies access.
Implementation of JWT Authentication
const jwt = require(‘jsonwebtoken’);
const express = require(‘express’);
const app = express();
const SECRET_KEY = “your_secret_key”;
// Middleware to verify token
const verifyToken = (req, res, next) => {
const token = req.header(‘Authorization’);
if (!token) return res.status(401).json({ error: “Access Denied” });
try {
req.user = jwt.verify(token, SECRET_KEY);
next();
} catch (err) {
res.status(403).json({ error: “Invalid Token” });
}
};
// Protected Route
app.get(‘/dashboard’, verifyToken, (req, res) => {
res.json({ message: “Welcome to the dashboard!” });
});
// Token Generation (Login Simulation)
app.post(‘/login’, (req, res) => {
const user = { id: 1, username: “user” };
const token = jwt.sign(user, SECRET_KEY, { expiresIn: ‘1h’ });
res.json({ token });
});
app.listen(3000, () => console.log(“Server running on port 3000”));
MongoDB Interview Questions
- What is MongoDB, and why is it used?
Answer: MongoDB is a NoSQL database that stores data in JSON-like documents.
Advantages-
- Schema-less & flexible.
- High scalability.
- Handles large data efficiently.
- Used in modern full-stack applications.
- What is indexing in MongoDB?
Answer: Indexing improves query performance.
Syntax to create an index- db.users.createIndex({ name: 1 }); // Ascending order
- What is aggregation in MongoDB?
Answer: Aggregation performs complex queries like filtering, grouping, and sorting.
Example-
db.users.aggregate([{ $group: { _id: “$city”, total: { $sum: 1 } } }]);
- What is the difference between populate() and lookup() in MongoDB?
Answer: populate is used in Mongoose for referencing collections while lookup() is Used in MongoDB aggregation for joining collections.
Example using populate()-
User.find().populate(“orders”).exec();
- How do you define a MongoDB schema and model in Mongoose?
Answer:
const mongoose = require(‘mongoose’);
const userSchema = new mongoose.Schema({
name: String,
age: Number
});
const User = mongoose.model(‘User’, userSchema);
- How do you perform CRUD operations in MongoDB with Mongoose?
Answer:
- Create: User.create({ name: “Tushar”, age: 25 })
- Read: User.find({ age: 25 })
- Update: User.updateOne({ name: “Tushar” }, { age: 26 })
- Delete: User.deleteOne({ name: “Tushar” })
- How do you perform transactions in MongoDB?
Answer: MongoDB supports ACID transactions for multi-document operations.
Example-
const session = await mongoose.startSession();
session.startTransaction();
try {
await User.updateOne({ _id: userId }, { $inc: { balance: -50 } }).session(session);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
}
session.endSession();
- What are database schema design best practices for MongoDB?
Answer:
- Use embedded documents for one-to-few relationships.
- Use references (populate()) for one-to-many relationships.
- Index frequently queried fields.
- What is the difference between SQL and NoSQL databases?
Answer:
Feature | SQL (Relational) | NoSQL (MongoDB) |
Structure | Table-based (rows & columns) | Document-based (JSON-like) |
Schema | Fixed schema (predefined structure) | Dynamic schema (flexible data storage) |
Scalability | Vertical (adding more power to the server) | Horizontal (adding more servers) |
Joins | Supports complex joins | No joins, but embedded documents |
Use Case | Best for structured data (banking, ERP) | Best for unstructured or semi-structured data (real-time analytics, IoT, social media) |
MongoDB, being NoSQL, is preferred in modern full-stack applications due to its flexibility and scalability.
- What is Sharding in MongoDB, and why is it important?
Answer:
Sharding is the process of distributing large datasets across multiple servers to improve performance and scalability in MongoDB. It allows horizontal scaling by partitioning data into smaller chunks and storing them across different shard nodes.
Why is Sharding Important?
- Handles Large Data Volumes: Distributes data across multiple servers, avoiding a single point of failure.
- Improves Performance: Queries can run in parallel on different shards, reducing response time.
- Horizontal Scalability: Instead of upgrading a single powerful server (vertical scaling), multiple servers handle the load.
How Sharding Works?
- Shard: A single MongoDB instance that holds a subset of data.
- Config Server: Stores metadata and manages shard mapping.
- Query Router (Mongos): Directs queries to the appropriate shard.
Example of Enabling Sharding in MongoDB-
// Enable sharding on the database
sh.enableSharding(“myDatabase”);
// Shard a collection based on a specific key
db.myCollection.createIndex({ userId: 1 });
sh.shardCollection(“myDatabase.myCollection”, { userId: 1 });
Sharding is essential for handling high-traffic applications and large datasets, making MongoDB a powerful choice for modern, scalable applications.
Mastering Full Stack Web Development concepts is essential for cracking interviews. This guide covered top 60 interview questions from JavaScript, React, Node.js, Express.js, MongoDB, and Redux.
Practice these topics, build projects, and stay updated with the latest web development trends. Real-world applications and hands-on coding will improve your confidence.
💡 Tip: Revise key concepts, write clean code, and focus on problem-solving skills.
🚀 Ready for your interview? Keep learning, keep coding, and ace your Full Stack Developer interview!
📢 Share this guide with friends preparing for tech interviews. Good luck! 🎯