> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MERN Stack Interview Questions

> Complete interview guide for MERN Stack developers covering MongoDB, Express.js, React, and Node.js -- with production scenarios, internals, and trade-off analysis at every level

The MERN stack (MongoDB, Express.js, React, Node.js) is one of the most popular full-stack combinations in the industry, and MERN interviews are uniquely challenging because they test breadth across four distinct technologies plus the integration patterns that connect them. The strongest candidates can trace a user action from a React click through Express middleware, into MongoDB, and back -- explaining the trade-offs at each layer. The questions below are organized by technology and progress from fundamentals to production-level scenarios within each section.

Each question includes what interviewers are really testing, what separates a textbook answer from a strong production-informed answer, common red flags, and follow-up questions designed to push your understanding deeper. Practice by answering each question out loud before reading the provided answer -- the interview is a conversation, not a written exam.

<hr />

## 1. MongoDB Fundamentals

<AccordionGroup>
  <Accordion title="What is MongoDB and its key features?">
    MongoDB is a **NoSQL document database** that stores data in flexible, JSON-like BSON documents rather than rows and columns. The way to think about it: if your data naturally looks like JSON objects with nested fields and arrays, MongoDB lets you store and query it that way without forcing it into rigid tables.

    **Key features:**

    * **Schema flexibility** -- documents in the same collection can have different fields, which is powerful for rapidly evolving products (e.g., an e-commerce catalog where shoes have "size" but laptops have "RAM")
    * **Horizontal scalability via sharding** -- distributes data across machines. MongoDB Atlas can auto-shard, which is how companies like Forbes and Toyota handle billions of documents
    * **Rich query language** -- supports filters, projections, regex, geospatial queries, and full-text search natively
    * **Aggregation framework** -- a pipeline-based data processing engine that can replace many use cases where you would otherwise need a separate analytics tool
    * **Replica sets** -- automatic failover with primary/secondary replication. In production, a 3-node replica set gives you zero-downtime reads even if one node dies
    * **Multi-document ACID transactions** (since v4.0) -- often overlooked, but MongoDB does support transactions when you need them

    **What interviewers are really testing:** Whether you understand *when* to choose MongoDB over a relational DB, not just what it is. They want to hear you talk about access patterns, not just features.

    **Red flag answer:** "MongoDB is a database that stores JSON." This is too shallow -- it misses why you would choose it and what trade-offs exist.

    **Follow-up:**

    1. When would you *not* choose MongoDB over PostgreSQL for a new project?
    2. What happens to write performance as your MongoDB collection grows from 1M to 100M documents without proper indexing?
    3. How does MongoDB's WiredTiger storage engine handle concurrency at the document level?
  </Accordion>

  <Accordion title="Explain BSON vs JSON">
    BSON (Binary JSON) is MongoDB's wire format -- a **binary-encoded serialization** of JSON-like documents. The key difference is not just "it's binary" but *why* it exists: BSON solves three problems JSON has for a database.

    **Key differences:**

    | Aspect     | JSON                                         | BSON                                                                     |
    | ---------- | -------------------------------------------- | ------------------------------------------------------------------------ |
    | Format     | Text-based (human-readable)                  | Binary (machine-optimized)                                               |
    | Data types | String, Number, Boolean, Array, Object, null | All JSON types + Date, ObjectId, Binary, Decimal128, Int32, Int64, Regex |
    | Traversal  | Must parse entire string                     | Length-prefixed -- can skip fields without parsing them                  |
    | Size       | Often smaller for simple docs                | Slightly larger due to metadata, but faster to decode                    |

    **Why BSON matters in practice:**

    * **ObjectId** is a 12-byte BSON type that encodes timestamp + machine ID + process ID + counter, giving you globally unique IDs without coordination -- this is why MongoDB can generate IDs client-side without hitting the server
    * **Decimal128** prevents floating-point precision bugs in financial data (e.g., `0.1 + 0.2 !== 0.3` in JSON/JS, but Decimal128 handles it correctly)
    * **Length-prefixed encoding** means MongoDB can scan through documents and skip irrelevant fields without deserializing them -- critical for query performance on large documents

    **What interviewers are really testing:** Whether you understand the *engineering trade-offs* behind format choices, not just definitions. A strong candidate connects BSON to real performance implications.

    **Red flag answer:** "BSON is just binary JSON." This misses the entire point of why it exists.

    **Follow-up:**

    1. If BSON documents are larger than JSON, why does MongoDB still use BSON instead of just compressing JSON?
    2. How does the ObjectId structure help with sorting by insertion time without a separate `createdAt` field?
    3. What happens when you store a JavaScript `Date` object vs a string date in MongoDB -- how does the query engine treat them differently?
  </Accordion>

  <Accordion title="What are collections and documents?">
    **Documents** are the fundamental unit of data in MongoDB -- think of them as self-contained JSON objects that represent a single entity (a user, an order, a product). Unlike SQL rows, a document can contain nested objects and arrays, so you can model an entire entity with its relationships in one place.

    **Collections** are groups of documents -- analogous to tables, but without enforced schema. Documents in the same collection can have completely different fields.

    **Key nuances most candidates miss:**

    * **Capped collections** -- fixed-size collections that overwrite oldest docs when full. Used for logging (e.g., storing the last 10M log entries with automatic rotation). Created with `db.createCollection("logs", { capped: true, size: 104857600 })`
    * **Schema validation** -- despite being "schemaless," production MongoDB almost always uses JSON Schema validation rules: `db.createCollection("users", { validator: { $jsonSchema: { ... } } })`. The flexibility is not about having *no* schema, but about evolving it without downtime migrations
    * **Document size limit** -- 16MB per document. This sounds large but becomes a real constraint when embedding arrays that grow unboundedly (e.g., embedding all comments inside a blog post document)
    * **The `_id` field is automatically indexed** and must be unique within a collection. If you do not provide it, MongoDB generates an ObjectId

    **What interviewers are really testing:** Whether you can translate relational thinking to document modeling. "Collections are like tables" is the starting point, not the answer.

    **Red flag answer:** "Collections are tables and documents are rows." This is technically correct but shows no understanding of the fundamental modeling differences.

    **Follow-up:**

    1. When would you split data across two collections vs embedding it in one document?
    2. What happens when a document exceeds the 16MB size limit? How do you redesign to avoid this?
    3. How do you handle schema evolution in MongoDB when a field needs to change type across millions of existing documents?
  </Accordion>

  <Accordion title="Explain CRUD operations">
    CRUD operations are the four fundamental data manipulation operations. In MongoDB, each has important nuances beyond the basic syntax:

    **Create:**

    * `insertOne()` -- inserts a single document. Returns `insertedId`
    * `insertMany()` -- inserts an array of documents. By default uses **ordered insert** (stops on first error). Pass `{ ordered: false }` for bulk imports where you want to continue past failures -- critical for ETL pipelines where you might be inserting 100K docs and a few have duplicate `_id` values

    **Read:**

    * `find()` -- returns a **cursor**, not an array. This is important: cursors are lazy and stream results, so querying 1M documents does not load them all into memory
    * `findOne()` -- returns a single document or null. Internally adds `limit(1)` to the query
    * **Projections** are critical for performance: `find({ status: "active" }, { name: 1, email: 1 })` only returns the fields you need, reducing network transfer and memory usage

    **Update:**

    * `updateOne()` / `updateMany()` -- uses update operators like `$set`, `$inc`, `$push`, `$pull`. The gotcha: without `$set`, you will replace the entire document
    * `findOneAndUpdate()` -- atomically finds and updates, returning either the old or new document (controlled by `returnDocument: "after"`). Essential for race-condition-safe operations like incrementing a counter
    * `replaceOne()` -- replaces the entire document except `_id`. Different from `updateOne` with `$set`

    **Delete:**

    * `deleteOne()` / `deleteMany()` -- permanent removal
    * **Soft deletes** are a common production pattern: `updateOne({ _id }, { $set: { deletedAt: new Date() } })` instead of actually deleting, allowing recovery and audit trails

    **What interviewers are really testing:** Do you know the difference between `updateOne` and `replaceOne`? Do you understand cursors vs arrays? Do you think about atomicity?

    **Red flag answer:** Listing the method names without explaining when to use which, or not knowing that `find()` returns a cursor.

    **Follow-up:**

    1. What is the difference between `updateOne` with `$set` and `replaceOne`? When would you use each?
    2. You need to insert 500K documents as fast as possible. How do you approach this?
    3. How do you implement an atomic "transfer funds" operation between two user documents?
  </Accordion>

  <Accordion title="What is the _id field?">
    The `_id` field is MongoDB's **mandatory primary key** -- every document must have one, it must be unique within its collection, and it is automatically indexed. If you do not provide it, MongoDB generates a 12-byte **ObjectId**.

    **ObjectId structure (12 bytes):**

    * Bytes 1-4: Unix timestamp (seconds since epoch)
    * Bytes 5-9: Random value (unique per machine/process)
    * Bytes 10-12: Incrementing counter

    **Why this matters in practice:**

    * **Sortable by creation time** -- since the first 4 bytes are a timestamp, sorting by `_id` gives you chronological order for free. `db.users.find().sort({ _id: 1 })` returns documents in insertion order without needing a `createdAt` field
    * **Globally unique without coordination** -- unlike auto-incrementing SQL IDs, ObjectIds can be generated on the client or across multiple shards without a central authority. This is what makes MongoDB horizontally scalable
    * **You can extract the timestamp**: `ObjectId("507f1f77bcf86cd799439011").getTimestamp()` returns the creation date

    **Custom `_id` values:**
    You can use any unique value as `_id` -- strings, numbers, even embedded documents. A common production pattern: using a natural key like `{ _id: "user_john@example.com" }` for collections where you always query by that key, saving an index.

    **What interviewers are really testing:** Whether you understand the implications of `_id` design on sharding, indexing, and query patterns -- not just that it exists.

    **Red flag answer:** "It's just an auto-generated unique ID." This misses the engineering behind ObjectId and the option to customize it.

    **Follow-up:**

    1. Why is using an auto-incrementing integer as `_id` problematic in a sharded MongoDB cluster?
    2. You notice that inserts are slow on a sharded collection. How might the `_id` (shard key) be causing a hotspot?
    3. Can two documents in *different* collections have the same `_id` value? Why or why not?
  </Accordion>
</AccordionGroup>

<hr />

## 2. MongoDB Advanced Concepts

<AccordionGroup>
  <Accordion title="What is indexing?">
    An index in MongoDB is a **B-tree data structure** (WiredTiger uses B+ trees) that stores a sorted subset of document fields, allowing the query engine to find matching documents without scanning every document in the collection (a "collection scan" or COLLSCAN).

    **Index types and when to use each:**

    | Type         | Syntax                                                            | Use Case                                              |
    | ------------ | ----------------------------------------------------------------- | ----------------------------------------------------- |
    | Single field | `{ email: 1 }`                                                    | Queries filtering on one field                        |
    | Compound     | `{ status: 1, createdAt: -1 }`                                    | Queries filtering/sorting on multiple fields          |
    | Multikey     | `{ tags: 1 }` (on an array field)                                 | Querying array contents                               |
    | Text         | `{ description: "text" }`                                         | Full-text search                                      |
    | Geospatial   | `{ location: "2dsphere" }`                                        | Location-based queries                                |
    | TTL          | `{ expiresAt: 1 }, { expireAfterSeconds: 0 }`                     | Auto-deleting expired documents (sessions, OTPs)      |
    | Partial      | `{ email: 1 }, { partialFilterExpression: { status: "active" } }` | Index only documents matching a filter -- saves space |

    **The ESR rule (Equality, Sort, Range):**
    When designing compound indexes, put Equality fields first, then Sort fields, then Range fields. For example, for a query `{ status: "active", createdAt: { $gte: lastWeek } }` sorted by `{ name: 1 }`, the optimal index is `{ status: 1, name: 1, createdAt: 1 }`.

    **Production gotchas:**

    * Each index costs \~8KB of RAM per 1000 documents. A collection with 50M docs and 10 indexes can consume several GB of RAM just for indexes
    * **Index intersection** exists but is often slower than a single compound index -- do not rely on MongoDB combining two single-field indexes efficiently
    * Use `explain("executionStats")` to verify your index is actually being used. The `IXSCAN` stage means index usage; `COLLSCAN` means full scan
    * Building indexes on large collections blocks writes by default. Use `{ background: true }` (deprecated in v4.2+; now indexes are built with an optimized hybrid approach)

    **What interviewers are really testing:** Can you design the right index for a given query pattern, and do you understand the write-performance trade-off?

    **Red flag answer:** "Indexes make queries faster." Without understanding write overhead, the ESR rule, or how to verify index usage with `explain()`.

    **Follow-up:**

    1. You have a compound index `{ a: 1, b: 1, c: 1 }`. Which queries will use this index and which will not?
    2. How would you index a field that contains arrays of objects (e.g., `orders[].productId`)?
    3. Your production database has 20 indexes on a collection but writes are slow. How do you decide which indexes to remove?
  </Accordion>

  <Accordion title="Explain aggregation framework">
    The aggregation framework is MongoDB's **data processing pipeline** -- it processes documents through sequential stages where each stage transforms the data and passes results to the next. Think of it like Unix pipes: `cat file | grep "error" | sort | uniq -c`.

    **Core stages you must know:**

    | Stage      | Purpose                                              | Example                                                             |
    | ---------- | ---------------------------------------------------- | ------------------------------------------------------------------- |
    | `$match`   | Filter documents (like `find()`)                     | `{ $match: { status: "active" } }`                                  |
    | `$group`   | Group by field and aggregate                         | `{ $group: { _id: "$city", total: { $sum: "$amount" } } }`          |
    | `$project` | Reshape documents (include/exclude/compute fields)   | `{ $project: { fullName: { $concat: ["$first", " ", "$last"] } } }` |
    | `$sort`    | Sort results                                         | `{ $sort: { total: -1 } }`                                          |
    | `$lookup`  | Left outer join with another collection              | Joins orders with users                                             |
    | `$unwind`  | Deconstruct an array field into separate documents   | Flatten `tags: ["a","b"]` into two docs                             |
    | `$facet`   | Run multiple pipelines in parallel on the same input | Get counts AND top results in one query                             |
    | `$bucket`  | Group documents into ranges                          | Revenue by price brackets                                           |

    **Real-world example -- sales dashboard:**

    ```javascript theme={null}
    db.orders.aggregate([
      { $match: { createdAt: { $gte: ISODate("2024-01-01") } } },
      { $group: {
          _id: { month: { $month: "$createdAt" }, product: "$productName" },
          revenue: { $sum: "$amount" },
          count: { $sum: 1 }
      }},
      { $sort: { revenue: -1 } },
      { $limit: 10 }
    ]);
    ```

    **Performance rules:**

    * **Put `$match` first** -- it filters documents early, reducing work for downstream stages, and can use indexes
    * **`$match` followed by `$sort`** can use a compound index. Once you hit a `$group` or `$project`, indexes are no longer used
    * For large datasets, use `{ allowDiskUse: true }` -- aggregation has a 100MB RAM limit per stage by default
    * `$lookup` (joins) can be expensive. If you are doing `$lookup` on every query, your schema design might need denormalization

    **What interviewers are really testing:** Can you solve a real analytics problem with the aggregation pipeline? Can you reason about stage ordering for performance?

    **Red flag answer:** Listing stage names without explaining how stage order impacts performance or when to use aggregation vs application-level processing.

    **Follow-up:**

    1. How would you compute a "running total" or "moving average" using the aggregation framework?
    2. When would you choose to process data in the application layer (Node.js) vs the aggregation pipeline?
    3. You have a `$lookup` that joins 10M orders with 1M users. It is slow. What are your optimization options?
  </Accordion>

  <Accordion title="What is sharding?">
    Sharding is MongoDB's strategy for **horizontal scaling** -- distributing data across multiple machines (shards) so no single server has to hold or process the entire dataset. Each shard holds a subset of the data determined by the **shard key**.

    **Architecture components:**

    * **Shards** -- individual replica sets that each hold a portion of the data
    * **Config servers** -- store metadata about which data lives on which shard (the "chunk map")
    * **mongos router** -- query router that clients connect to. It reads the config servers to know which shard to send queries to

    **Shard key selection is the most critical decision:**

    * A bad shard key creates **hotspots** -- e.g., sharding by `createdAt` sends all new writes to the last shard
    * A good shard key has **high cardinality** (many unique values), **even distribution**, and **query isolation** (most queries target one shard, not all)
    * Example: sharding an e-commerce orders collection by `{ userId: "hashed" }` distributes writes evenly but means queries like "all orders this week" must scatter-gather across all shards
    * Example: sharding by `{ region: 1, userId: 1 }` enables zone sharding where US data stays on US servers (data residency compliance)

    **Production realities:**

    * Once you shard, you **cannot change the shard key** (pre-v5.0; v5.0+ allows resharding but it is an expensive operation)
    * Scatter-gather queries (queries that do not include the shard key) hit all shards and are much slower
    * MongoDB recommends sharding when your dataset exceeds what a single replica set can handle (typically 2-5TB or when write throughput exceeds what one primary can handle)
    * **Chunk splitting and balancing** happen automatically -- MongoDB moves chunks between shards to maintain even distribution, but this migration consumes I/O

    **What interviewers are really testing:** Do you understand shard key design trade-offs? This is a senior-level question that separates candidates who have operated MongoDB at scale from those who have only read the docs.

    **Red flag answer:** "Sharding splits data across servers for scalability" without discussing shard key selection, hotspots, or scatter-gather queries.

    **Follow-up:**

    1. You chose `{ email: 1 }` as your shard key. A year later, your write throughput is bottlenecked. What went wrong and how do you fix it?
    2. Explain the difference between hashed sharding and ranged sharding. When would you choose each?
    3. How does MongoDB handle a query that does not include the shard key in the filter?
  </Accordion>

  <Accordion title="Explain replica sets">
    A replica set is a group of MongoDB instances (typically 3 or more) that maintain **identical copies of the same data** for high availability and data durability. One node is the **primary** (handles all writes), and the others are **secondaries** (replicate the primary's oplog and can serve reads).

    **How replication works internally:**

    * The primary writes operations to a capped collection called the **oplog** (operations log)
    * Secondaries continuously tail the primary's oplog and apply the same operations locally
    * This is **asynchronous replication** by default -- secondaries may lag behind the primary (replication lag)

    **Automatic failover:**

    * If the primary becomes unreachable, the remaining members hold an **election** using the Raft consensus algorithm (since v3.2)
    * A secondary with the most up-to-date oplog wins and becomes the new primary
    * Failover typically completes in **10-30 seconds** -- during this window, writes fail
    * Applications using the MongoDB driver with `retryWrites: true` automatically retry failed writes after failover

    **Read preferences (production decision):**

    | Read Preference     | Behavior                         | Trade-off                            |
    | ------------------- | -------------------------------- | ------------------------------------ |
    | `primary` (default) | All reads from primary           | Consistent but adds load             |
    | `primaryPreferred`  | Primary unless unavailable       | Good default for most apps           |
    | `secondary`         | Reads from secondaries only      | May return stale data                |
    | `nearest`           | Reads from lowest-latency member | Best for geo-distributed deployments |

    **Write concern -- the durability knob:**

    * `w: 1` -- acknowledged after primary writes (default)
    * `w: "majority"` -- acknowledged after majority of nodes write. Prevents data loss during failover but adds latency (\~2-5ms extra)
    * `w: 0` -- fire-and-forget. Fast but dangerous

    **What interviewers are really testing:** Whether you understand the CAP theorem trade-offs in practice -- consistency vs availability vs latency in replica sets.

    **Red flag answer:** "Replica sets copy data for backup." This confuses replication with backups and misses the HA and consistency implications.

    **Follow-up:**

    1. What is replication lag, and how does it affect reads from secondaries in a real-time application?
    2. You have a 3-node replica set and 2 nodes go down. Can the remaining node accept writes? Why or why not?
    3. How does write concern `"majority"` prevent a specific data loss scenario that `w: 1` does not?
  </Accordion>

  <Accordion title="What are embedded vs referenced relationships?">
    This is arguably the **most important MongoDB design decision** you will make. Choosing wrong leads to either slow reads (too much referencing) or unbounded document growth (too much embedding).

    **Embedding (denormalized):** Related data lives inside the same document.

    ```javascript theme={null}
    // User with embedded addresses
    {
      _id: ObjectId("..."),
      name: "Sarah",
      addresses: [
        { type: "home", city: "Austin", zip: "73301" },
        { type: "work", city: "Dallas", zip: "75001" }
      ]
    }
    ```

    **Referencing (normalized):** Related data lives in separate collections, linked by `_id`.

    ```javascript theme={null}
    // User document
    { _id: ObjectId("user1"), name: "Sarah" }
    // Address documents
    { _id: ObjectId("addr1"), userId: ObjectId("user1"), city: "Austin" }
    { _id: ObjectId("addr2"), userId: ObjectId("user1"), city: "Dallas" }
    ```

    **Decision framework -- embed when:**

    * Data is always accessed together (e.g., user + their shipping addresses)
    * The embedded array has a **bounded, small size** (e.g., max 5 addresses)
    * You need atomic updates on both parent and child (single-document atomicity)
    * The relationship is one-to-few

    **Reference when:**

    * Data grows unboundedly (e.g., user + their 50K comments over years)
    * Data is accessed independently (e.g., products and reviews have different read patterns)
    * The embedded document would exceed 16MB
    * The relationship is one-to-many or many-to-many
    * Multiple entities reference the same data (normalization avoids duplication)

    **Hybrid pattern (the real-world answer):**
    Embed a summary and reference the full data. For example, a blog post embeds the author's `name` and `avatarUrl` (for display) but references `authorId` (for the full profile). This avoids a `$lookup` for the common read path.

    **The "subset pattern":** Embed only the most recent N items (e.g., last 10 reviews) and store the full history in a separate collection.

    **What interviewers are really testing:** Data modeling judgment. The correct answer is always "it depends on access patterns," but you must be able to articulate *specific* criteria for each choice.

    **Red flag answer:** Always embedding or always referencing without considering access patterns, document size limits, or write frequency.

    **Follow-up:**

    1. You embedded user comments inside blog posts. Six months later, popular posts have 50K comments and the app is slow. How do you redesign?
    2. How does the "bucket pattern" help with time-series data in MongoDB?
    3. When would you use MongoDB's `$lookup` for referencing, and what is its performance limitation compared to SQL JOINs?
  </Accordion>

  <Accordion title="How do MongoDB transactions work, and when should you use them?">
    Since MongoDB 4.0 (replica sets) and 4.2 (sharded clusters), MongoDB supports **multi-document ACID transactions** -- the same guarantees you get from SQL databases.

    **How they work:**

    ```javascript theme={null}
    const session = client.startSession();
    try {
      session.startTransaction();
      await accounts.updateOne(
        { _id: "alice" },
        { $inc: { balance: -100 } },
        { session }
      );
      await accounts.updateOne(
        { _id: "bob" },
        { $inc: { balance: 100 } },
        { session }
      );
      await session.commitTransaction();
    } catch (error) {
      await session.abortTransaction();
    } finally {
      session.endSession();
    }
    ```

    **When to use transactions:**

    * Financial operations (transfers, payments) where partial updates are unacceptable
    * Multi-collection updates that must be atomic (e.g., creating an order AND reducing inventory)
    * Any operation where you need "all or nothing" semantics

    **When NOT to use them (the experienced take):**

    * If you can model the operation as a **single-document update**, you do not need a transaction -- single-document operations are already atomic in MongoDB
    * Transactions add latency (extra round trips, lock contention) and should not be your default tool
    * Most experienced MongoDB developers redesign their schema to avoid needing transactions rather than reaching for them. This is a fundamental difference from SQL-first thinking
    * Transactions have a **60-second default timeout** and hold locks, so long-running transactions block other operations

    **What interviewers are really testing:** Whether you default to transactions (SQL mindset) or think about schema design to avoid them (MongoDB mindset). The best answer acknowledges both options.

    **Red flag answer:** "MongoDB doesn't support transactions" (outdated) or "I always use transactions for safety" (misses the performance implications).

    **Follow-up:**

    1. How does MongoDB implement snapshot isolation for transactions, and what are the performance implications?
    2. If a transaction fails mid-way on a sharded cluster, how does MongoDB ensure consistency across shards?
    3. Redesign a "transfer funds" operation so it does not require a multi-document transaction.
  </Accordion>

  <Accordion title="What is the MongoDB Change Streams feature and how would you use it?">
    Change Streams let you **subscribe to real-time data changes** in a collection, database, or entire cluster. They are built on top of the oplog and provide a reliable, resumable stream of insert/update/delete events.

    **Basic usage:**

    ```javascript theme={null}
    const changeStream = db.collection("orders").watch();

    changeStream.on("change", (change) => {
      console.log("Operation:", change.operationType);
      console.log("Document:", change.fullDocument);
      // operationType: "insert", "update", "replace", "delete"
    });
    ```

    **Real-world use cases:**

    * **Real-time notifications** -- notify users when their order status changes
    * **Cache invalidation** -- invalidate Redis cache when source data changes
    * **Event-driven architectures** -- trigger downstream services when data changes (e.g., send email when user registers)
    * **Data synchronization** -- keep Elasticsearch or analytics databases in sync with MongoDB
    * **Audit logging** -- record every change for compliance

    **Production considerations:**

    * Change streams require a **replica set** (even a single-node replica set for development)
    * They support **resume tokens** -- if your listener crashes, you can resume from exactly where you left off without missing events
    * You can filter changes with a pipeline: `collection.watch([{ $match: { "fullDocument.status": "shipped" } }])`
    * Change streams use the oplog, so they add minimal overhead to the database

    **What interviewers are really testing:** Whether you know MongoDB has real-time capabilities beyond CRUD, and whether you can design event-driven systems.

    **Red flag answer:** Not knowing change streams exist, or suggesting polling the database on an interval instead.

    **Follow-up:**

    1. How would you handle a scenario where your change stream listener was down for 2 hours? Can you recover all missed events?
    2. Compare MongoDB Change Streams with using a separate message queue like Kafka. When would you choose each?
    3. What happens to change streams when a replica set failover occurs?
  </Accordion>

  <Accordion title="How do you handle schema migrations in MongoDB?">
    Unlike SQL databases with rigid schemas and migration files, MongoDB's flexible schema means migrations are a **different beast entirely**. There are two primary strategies:

    **1. Lazy migration (recommended for most cases):**
    Handle old and new schema versions in your application code. Update documents to the new schema only when they are accessed.

    ```javascript theme={null}
    // Application code handles both versions
    function normalizeUser(doc) {
      if (!doc.fullName && doc.firstName) {
        // Old schema: firstName + lastName
        doc.fullName = `${doc.firstName} ${doc.lastName}`;
      }
      return doc;
    }
    ```

    **2. Eager migration (for critical changes):**
    Run a script to update all documents at once. Use `bulkWrite` for performance.

    ```javascript theme={null}
    // Migrate all documents
    const cursor = db.users.find({ fullName: { $exists: false } });
    const ops = [];
    for await (const doc of cursor) {
      ops.push({
        updateOne: {
          filter: { _id: doc._id },
          update: { $set: { fullName: `${doc.firstName} ${doc.lastName}` },
                    $unset: { firstName: "", lastName: "" } }
        }
      });
      if (ops.length === 1000) {
        await db.users.bulkWrite(ops);
        ops.length = 0;
      }
    }
    ```

    **3. Schema version field pattern:**
    Add a `schemaVersion` field to every document and handle each version in code:

    ```javascript theme={null}
    { _id: 1, schemaVersion: 2, fullName: "Ali Khan" }
    { _id: 2, schemaVersion: 1, firstName: "Sara", lastName: "Ahmed" }
    ```

    **Tools:** `migrate-mongo` is a popular library that provides a SQL-migration-like workflow for MongoDB.

    **What interviewers are really testing:** Whether you understand that schema flexibility is not the same as "no schema management" -- and how you handle evolution at scale.

    **Red flag answer:** "MongoDB is schemaless so you don't need migrations." Every production MongoDB deployment needs a migration strategy.

    **Follow-up:**

    1. You need to rename a field used in 50M documents. What is your migration strategy to avoid downtime?
    2. How do you use MongoDB's `$jsonSchema` validator to enforce schema rules while still allowing gradual migration?
    3. What are the risks of lazy migration when running analytics queries that span old and new schema versions?
  </Accordion>
</AccordionGroup>

<hr />

## 3. Express.js Basics and Middleware

<AccordionGroup>
  <Accordion title="What is Express.js?">
    Express.js is a **minimal, un-opinionated web framework** for Node.js that sits as a thin abstraction over Node's built-in `http` module. It adds three things Node's raw HTTP server does not have: a **routing system**, a **middleware pipeline**, and **convenience methods** for request/response handling.

    **Why Express exists:** Node's native `http.createServer()` gives you a raw request and response object. You would have to manually parse URLs, handle different HTTP methods, parse request bodies, set headers, and manage error handling yourself. Express does all of this with a clean API.

    **What Express does NOT do (and why this matters):**

    * No built-in ORM or database layer -- you choose (Mongoose, Prisma, Sequelize)
    * No built-in authentication -- you add Passport, JWT, or custom middleware
    * No built-in validation -- you add Zod, Joi, or express-validator
    * No built-in view engine -- you add EJS, Pug, or just send JSON

    This un-opinionated design is why Express dominates the Node.js ecosystem: it does not lock you into decisions. Compare this with NestJS (opinionated, Angular-style) or Fastify (performance-focused with schema validation).

    **What interviewers are really testing:** Whether you understand Express's role in the stack and can articulate why you would (or would not) choose it over alternatives like Fastify, Koa, or NestJS.

    **Red flag answer:** "Express is a Node.js framework for building websites." Too vague -- does not mention middleware, routing, or how it relates to Node's http module.

    **Follow-up:**

    1. When would you choose Fastify over Express for a new project, and why?
    2. Express has not had a major release in years. What does that mean for its production readiness?
    3. How does Express compare to Koa in terms of middleware composition?
  </Accordion>

  <Accordion title="Explain middleware">
    Middleware is the **core architectural pattern** of Express. A middleware function receives `(req, res, next)` and can do one of three things: (1) modify `req` or `res`, (2) end the request-response cycle, or (3) call `next()` to pass control to the next middleware.

    **The mental model:** Think of middleware as a **pipeline of functions** that a request flows through. Each function can inspect, modify, or short-circuit the request. This is the Chain of Responsibility pattern.

    **Execution order matters critically:**

    ```javascript theme={null}
    // This works: body parser runs BEFORE the route handler
    app.use(express.json());
    app.post("/users", (req, res) => res.json(req.body));

    // This BREAKS: body parser runs AFTER the route
    app.post("/users", (req, res) => res.json(req.body)); // req.body is undefined
    app.use(express.json());
    ```

    **The four types and when each matters:**

    * **Application-level** (`app.use()`) -- runs for every request. Use for logging, CORS, body parsing
    * **Router-level** (`router.use()`) -- scoped to a specific router. Use for sub-application middleware like auth on `/admin` routes
    * **Error-handling** (`(err, req, res, next)`) -- the 4-parameter signature tells Express this is an error handler. Must be declared last
    * **Third-party** -- `cors()`, `helmet()`, `morgan()`. These are just functions that return middleware

    **What interviewers are really testing:** Whether you understand middleware ordering, the difference between `next()` and `next(err)`, and how the middleware pipeline affects request processing.

    **Red flag answer:** Defining middleware without explaining the pipeline concept, execution order, or the importance of calling `next()`.

    **Follow-up:**

    1. What happens if a middleware calls both `res.send()` AND `next()`? Is that valid?
    2. How does Express know the difference between a regular middleware and an error-handling middleware?
    3. You have 15 middleware functions. Requests are slow. How do you identify which middleware is the bottleneck?
  </Accordion>

  <Accordion title="How does routing work?">
    Routing in Express maps **HTTP method + URL path** combinations to handler functions. Express internally uses the `path-to-regexp` library to compile route patterns into regular expressions for efficient matching.

    **Route matching rules (order matters):**

    * Routes are matched **in the order they are defined** -- first match wins
    * Exact matches take priority over parameterized routes only if defined first
    * `app.use("/api")` matches `/api`, `/api/users`, `/api/anything` (prefix matching)
    * `app.get("/api")` matches only `/api` exactly (exact matching)

    **Router composition (the production pattern):**

    ```javascript theme={null}
    // routes/users.js
    const router = express.Router();
    router.get("/", getAllUsers);
    router.get("/:id", getUserById);
    router.post("/", createUser);
    module.exports = router;

    // app.js
    app.use("/api/users", require("./routes/users"));
    app.use("/api/orders", require("./routes/orders"));
    ```

    **Route methods:** `app.get()`, `app.post()`, `app.put()`, `app.patch()`, `app.delete()`, `app.all()` (matches any method), `app.route()` (chain methods for the same path)

    **What interviewers are really testing:** Whether you understand route ordering bugs, router composition for modular apps, and the difference between `app.use()` prefix matching and `app.get()` exact matching.

    **Red flag answer:** Only describing basic `app.get("/path", handler)` without mentioning route ordering, Router composition, or prefix vs exact matching.

    **Follow-up:**

    1. You have `app.get("/users/:id")` and `app.get("/users/admin")`. A request to `/users/admin` hits the first route with `id = "admin"`. How do you fix this?
    2. How does Express handle a request that matches no routes?
    3. What is the performance difference between having 500 routes on `app` directly vs using `express.Router()` to organize them?
  </Accordion>

  <Accordion title="What are route parameters?">
    Route parameters capture **dynamic segments** from the URL path, while query strings pass optional key-value pairs. Understanding the distinction matters for API design.

    **Route parameters (`req.params`):** Identify a specific resource.

    ```javascript theme={null}
    // /users/42 -> req.params.id = "42"
    app.get("/users/:id", (req, res) => {
      // Always a string -- you must parse if you need a number
      const userId = parseInt(req.params.id, 10);
    });
    ```

    **Query strings (`req.query`):** Filter, sort, or paginate resources.

    ```javascript theme={null}
    // /users?role=admin&page=2 -> req.query = { role: "admin", page: "2" }
    app.get("/users", (req, res) => {
      const { role, page = 1, limit = 10 } = req.query;
    });
    ```

    **Key design principle:** Use route params for **required, resource-identifying** values. Use query strings for **optional, filtering/sorting** values. `/users/42` identifies user 42. `/users?role=admin&sort=name` filters and sorts the users collection.

    **Validation is critical:** `req.params.id` is always a string, and it can be anything the client sends -- including SQL injection attempts, excessively long strings, or special characters. Always validate and sanitize.

    **What interviewers are really testing:** API design instincts and security awareness.

    **Red flag answer:** Not mentioning that params are always strings, or not considering validation/sanitization.

    **Follow-up:**

    1. When would you use `/users/:userId/orders/:orderId` vs `/orders/:orderId`? What are the trade-offs of nested routes?
    2. How do you validate that `:id` is a valid MongoDB ObjectId before it reaches your database query?
    3. What is the difference between `req.params`, `req.query`, and `req.body`? When should each be used in REST API design?
  </Accordion>

  <Accordion title="How to handle POST requests?">
    Handling POST requests requires **body parsing middleware** because Express does not parse request bodies by default -- `req.body` is `undefined` unless you add a parser.

    **Essential middleware:**

    ```javascript theme={null}
    app.use(express.json()); // Parses Content-Type: application/json
    app.use(express.urlencoded({ extended: true })); // Parses Content-Type: application/x-www-form-urlencoded
    ```

    **The `extended` option matters:** `extended: true` uses the `qs` library (supports nested objects like `user[name]=Ali`), while `extended: false` uses `querystring` (flat key-value pairs only). For APIs receiving form data with nested structures, use `true`.

    **Production-grade POST handling:**

    ```javascript theme={null}
    app.use(express.json({ limit: "10kb" })); // Prevent payload bombs

    app.post("/users", async (req, res, next) => {
      try {
        // 1. Validate input
        const validated = userSchema.parse(req.body); // Zod validation
        // 2. Business logic
        const user = await userService.create(validated);
        // 3. Respond with 201 + Location header
        res.status(201).location(`/users/${user.id}`).json(user);
      } catch (err) {
        next(err);
      }
    });
    ```

    **What most candidates miss:**

    * Set a `limit` on `express.json()` to prevent denial-of-service via large payloads (default is 100kb, but 10kb is often sufficient for API requests)
    * Return `201 Created` (not `200 OK`) for successful resource creation
    * For file uploads, `express.json()` does not work -- you need `multer` or `busboy`
    * The `Content-Type` header must match the parser, or `req.body` will be empty/undefined

    **What interviewers are really testing:** Whether you handle POST requests defensively -- validation, size limits, correct status codes, error handling.

    **Red flag answer:** Just showing `app.post("/path", (req, res) => res.json(req.body))` without validation, error handling, or mentioning the body parser middleware.

    **Follow-up:**

    1. A client sends a POST with `Content-Type: text/plain`. What happens with `express.json()` middleware? How do you handle it?
    2. How do you handle multipart/form-data (file uploads) in Express?
    3. What is the difference between `express.json()` and the deprecated `body-parser` package?
  </Accordion>

  <Accordion title="What is Express.js and why is it used?">
    Express.js is a minimal and flexible Node.js web framework that simplifies handling HTTP requests, routing, and middleware integration. It acts as a wrapper around Node's HTTP module, providing a clean abstraction to build REST APIs and web applications.

    ## Example:

    ```javascript theme={null}
    const express = require('express');
    const app = express();

    app.get('/', (req, res) => {
      res.send('Hello from Express!');
    });

    app.listen(3000, () => console.log('Server running on port 3000'));
    ```

    ## Why:

    Because Node's native HTTP module is low-level -- you would manually parse URLs, handle routing with `if/else` chains, parse JSON bodies with `Buffer` concatenation, and manage error propagation yourself. Express provides clean abstractions for all of this.

    ## When:

    Use it when building REST APIs, microservices, or server-rendered web apps. For new projects in 2024+, also consider Fastify (2-3x faster due to schema-based serialization) or Hono (edge-first, works on Cloudflare Workers).

    ## Where:

    Express powers approximately 60% of Node.js web applications in production. Companies like Uber, IBM, and Accenture use it. It is the default choice in most MERN stack tutorials and bootcamps, which contributes to its ecosystem dominance.

    **What interviewers are really testing:** Do you just know Express, or do you understand *why* it exists and what alternatives you would consider?

    **Red flag answer:** "Express is a framework for making servers." No mention of middleware architecture, Node.js HTTP module relationship, or when you would choose alternatives.

    **Follow-up:**

    1. If you were starting a new high-performance API from scratch today, would you still choose Express? Why or why not?
    2. How does Express's middleware model differ from Koa's `async/await`-based middleware?
    3. Express 5 has been in alpha for years. What problems does it solve that Express 4 does not?
  </Accordion>

  <Accordion title="Explain the middleware concept in Express.js">
    Middleware functions are functions that execute during the request-response cycle. They have access to req, res, and next() — used to modify requests, handle authentication, validation, logging, etc.

    ## Example:

    ```javascript theme={null}
    function logger(req, res, next) {
      console.log(`${req.method} ${req.url}`);
      next(); // Pass control to next middleware
    }

    app.use(logger);
    app.get('/', (req, res) => res.send('Home'));
    ```

    ## Why:

    Middleware provides a way to modularize logic -- logging, authentication, validation -- without polluting route handlers. Without middleware, you would duplicate auth checks, logging, and error handling inside every single route handler.

    ## When:

    Use middleware whenever you want to perform an action before reaching your route (or after response, like error logging). A production Express app typically has 5-15 middleware layers before any route handler executes.

    ## Where:

    Common production middleware stack (in order):

    * `helmet()` -- security headers (first, because it protects everything below)
    * `cors()` -- CORS handling
    * `morgan()` or custom logger -- request logging
    * `express.json()` -- body parsing
    * Rate limiter -- abuse prevention
    * Auth middleware -- token verification
    * Route handlers
    * Error handler (always last)

    **What interviewers are really testing:** Whether you understand that middleware order is not arbitrary -- it is a carefully designed pipeline where each layer depends on the ones before it.

    **Red flag answer:** Describing middleware as "functions that run before routes" without explaining the pipeline, `next()`, or order significance.

    **Follow-up:**

    1. What happens to your app if an early middleware throws an uncaught exception? How does Express handle it?
    2. Can middleware be async? What is the gotcha with async middleware in Express 4?
    3. How would you create a middleware that measures the response time of every request and logs it?
  </Accordion>

  <Accordion title="What types of middleware exist in Express.js?">
    | Type              | Description                        | Example                              |
    | ----------------- | ---------------------------------- | ------------------------------------ |
    | Application-level | Bound to app                       | `app.use()`                          |
    | Router-level      | Bound to an Express router         | `router.use()`                       |
    | Built-in          | Provided by Express                | `express.json()`, `express.static()` |
    | Third-party       | Installed via npm                  | `cors`, `helmet`, `morgan`           |
    | Error-handling    | 4 parameters (err, req, res, next) | Custom error middleware              |

    ## Example:

    ```javascript theme={null}
    // Error-handling middleware
    app.use((err, req, res, next) => {
      console.error(err.message);
      res.status(500).send('Internal Server Error');
    });
    ```

    ## Why:

    To create reusable, layered logic pipelines.

    ## When:

    Whenever you need pre/post-processing around route handlers.

    ## Where:

    Throughout the Express lifecycle (before/after routes).
  </Accordion>

  <Accordion title="What is the role of next() in middleware?">
    `next()` passes control to the next middleware in the stack. If not called, the request hangs (no response sent).

    ## Example:

    ```javascript theme={null}
    app.use((req, res, next) => {
      console.log('Before route');
      next(); // Pass to next middleware or route
    });

    app.get('/', (req, res) => {
      res.send('After middleware');
    });
    ```

    ## Why:

    To chain multiple middlewares for modular logic.

    ## When:

    When you need layered control (logging → validation → controller).

    ## Where:

    Always in custom middleware unless it ends the request.
  </Accordion>

  <Accordion title="What's the difference between app.use() and app.get()?">
    | Function  | Purpose                                                             |
    | --------- | ------------------------------------------------------------------- |
    | app.use() | Registers middleware (runs for all methods unless filtered by path) |
    | app.get() | Defines a route handler specifically for GET requests               |

    ## Example:

    ```javascript theme={null}
    app.use('/users', (req, res, next) => {
      console.log('Middleware for /users');
      next();
    });

    app.get('/users', (req, res) => res.send('User list'));
    ```

    ## Why:

    `use()` is for pre-processing, `get()` is for request handling.

    ## When:

    Use `use()` for shared logic like authentication.

    ## Where:

    Across all routes or specific prefixes.
  </Accordion>

  <Accordion title="How does Express handle the request-response lifecycle?">
    1. Request enters Express
    2. Passes through middleware stack
    3. If matched, route handler executes
    4. If no match → 404 handler
    5. If error → error-handling middleware

    ## Example Flow:

    ```
    Incoming Request
       ↓
    app.use(logger)
       ↓
    app.use(auth)
       ↓
    app.get('/users', controller)
       ↓
    app.use(errorHandler)
       ↓
    Response Sent
    ```

    ## Why:

    Understanding this helps you debug request flow and performance.

    ## When:

    When analyzing middleware order or debugging missed routes.

    ## Where:

    In Express core — it's what powers routing and middleware sequencing.
  </Accordion>

  <Accordion title="How do you handle errors globally in Express.js?">
    By using a custom error-handling middleware — identified by 4 parameters (err, req, res, next).

    ## Example:

    ```javascript theme={null}
    app.use((err, req, res, next) => {
      console.error(err.stack);
      res.status(500).json({ message: err.message });
    });

    // And to trigger it:
    app.get('/', (req, res, next) => {
      next(new Error('Something went wrong'));
    });
    ```

    ## Why:

    Centralized error handling avoids repeating try/catch everywhere.

    ## When:

    In production APIs, always define a global error middleware.

    ## Where:

    Place at the bottom of middleware stack (after routes).
  </Accordion>

  <Accordion title="What's the difference between res.send(), res.json(), and res.end()?">
    | Method     | Purpose                                 |
    | ---------- | --------------------------------------- |
    | res.send() | Sends response (auto-detects type)      |
    | res.json() | Sends JSON response (sets content-type) |
    | res.end()  | Ends response without data              |

    ## Example:

    ```javascript theme={null}
    res.send('Hello');
    res.json({ success: true });
    res.end(); // No data, just closes connection
    ```

    ## Why:

    Each method suits different scenarios (raw text vs structured data).

    ## When:

    Use:

    * `send()` → text or HTML
    * `json()` → APIs
    * `end()` → streams or empty responses

    ## Where:

    Controllers or route handlers.
  </Accordion>

  <Accordion title="How can you secure your Express app?">
    Key practices:

    1. Use Helmet → sets HTTP headers
    2. Use Rate-limiter → prevent brute-force
    3. Use CORS properly
    4. Use `express.json({ limit })` → prevent payload overflows
    5. Disable x-powered-by header
    6. Validate all inputs (with Joi/Zod)

    ## Example:

    ```javascript theme={null}
    const helmet = require('helmet');
    const rateLimit = require('express-rate-limit');

    app.use(helmet());
    app.use(rateLimit({ windowMs: 60 * 1000, max: 100 }));
    app.disable('x-powered-by');
    ```

    ## Why:

    Express is not secure by default; hardening prevents XSS, CSRF, and DoS attacks.

    ## When:

    Always in production environments.

    ## Where:

    At app initialization or middleware level.
  </Accordion>

  <Accordion title="How can you handle async errors in Express route handlers?">
    Async functions throw errors inside Promises, so you must use:

    1. Try/catch inside route, or
    2. Wrap with async error handler.

    ## Example:

    ```javascript theme={null}
    // Approach 1: try/catch
    app.get('/', async (req, res, next) => {
      try {
        const users = await User.find();
        res.json(users);
      } catch (err) {
        next(err);
      }
    });

    // Approach 2: wrapper function
    const asyncHandler = fn => (req, res, next) =>
      Promise.resolve(fn(req, res, next)).catch(next);
    ```

    ## Why:

    Express doesn't automatically catch async errors without `.catch()`.

    ## When:

    Always for async routes (DB calls, APIs).

    ## Where:

    Use asyncHandler pattern across all async routes.
  </Accordion>

  <Accordion title="How does Express handle routing internally?">
    Express maintains a router stack for every HTTP method and path. When a request comes in, it iterates through this stack and executes the first matching route or middleware.

    ## Example:

    ```javascript theme={null}
    app.get('/users', handler1);
    app.use('/users', handler2);
    ```

    The router internally uses the path-to-regexp library to match routes efficiently.

    ## Why:

    To provide performant routing and predictable middleware flow.

    ## When:

    When debugging routing conflicts or order issues.

    ## Where:

    Inside express/lib/router/layer.js and route.js source.
  </Accordion>

  <Accordion title="What are route parameters and how do you access them?">
    Route parameters are dynamic values in URL paths, accessible via `req.params`.

    ## Example:

    ```javascript theme={null}
    app.get('/users/:id', (req, res) => {
      res.send(`User ID: ${req.params.id}`);
    });
    ```

    ## Why:

    Used to identify specific resources (user by ID, post by slug).

    ## When:

    For REST endpoints like `/users/:id`, `/posts/:slug`.

    ## Where:

    Inside route handlers.
  </Accordion>
</AccordionGroup>

<hr />

## 4. Express.js Authentication & Authorization

<AccordionGroup>
  <Accordion title="What is the difference between authentication and authorization?">
    * **Authentication** → verifying identity (e.g., login with email/password or Google OAuth)
    * **Authorization** → verifying permissions (e.g., only admin can delete a user)

    ## Example:

    ```javascript theme={null}
    // Example route using both
    app.get('/admin', authenticateUser, authorizeRole('admin'), (req, res) => {
      res.send('Welcome Admin!');
    });
    ```

    ## Why:

    Separating these concerns improves scalability and security.

    ## When:

    Always implement authenticate first, then apply authorize on protected routes.

    ## Where:

    Middleware layer is the best place — reusable across routes.
  </Accordion>

  <Accordion title="How do you implement JWT authentication in Node.js?">
    JWT (JSON Web Token) is a stateless authentication mechanism — no need to store sessions in the database.

    ## Steps:

    1. User logs in with credentials
    2. Server verifies credentials and issues a signed JWT using jsonwebtoken
    3. Client stores JWT (usually in localStorage or cookie)
    4. Client sends JWT in `Authorization: Bearer <token>` header for protected routes

    ## Example:

    ```javascript theme={null}
    import jwt from 'jsonwebtoken';

    // Generate Token
    const token = jwt.sign({ userId: user.id, role: user.role }, process.env.JWT_SECRET, {
      expiresIn: '1h',
    });

    // Middleware for verification
    function verifyToken(req, res, next) {
      const token = req.headers.authorization?.split(' ')[1];
      if (!token) return res.status(401).json({ error: 'No token provided' });

      try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.user = decoded;
        next();
      } catch (err) {
        res.status(403).json({ error: 'Invalid token' });
      }
    }
    ```

    ## Why:

    JWT avoids database lookups on every request (unlike sessions). The token itself contains the user's identity and claims, so any server in a load-balanced cluster can verify it independently. This is critical for microservices where there is no shared session store.

    ## When:

    Use JWT for REST APIs and microservices. However, **do not blindly default to JWT** -- sessions with Redis are often simpler and more secure for monolithic apps. The main advantage of JWT is in distributed, stateless architectures.

    ## Where:

    Ideal for stateless systems or distributed apps (like mobile + web + microservices all sharing the same auth).

    **Critical security nuances most candidates miss:**

    * **Never store JWTs in localStorage** -- vulnerable to XSS. Use HttpOnly cookies instead
    * **Always set short expiration** (15 minutes for access tokens) and use refresh tokens for longevity
    * **Include only necessary claims** -- the payload is Base64-encoded, not encrypted. Anyone can decode it
    * **Use RS256 (asymmetric) for microservices** instead of HS256 (symmetric), so services can verify tokens without knowing the secret
    * **Validate the `alg` header** -- the "none algorithm" attack changes `alg` to `"none"` to bypass signature verification

    **What interviewers are really testing:** Whether you understand JWT security pitfalls, not just how to generate tokens.

    **Red flag answer:** Storing JWT in localStorage, not mentioning token expiration, or not knowing the difference between HS256 and RS256.

    **Follow-up:**

    1. A user changes their password. How do you invalidate all their existing JWTs?
    2. What is the "none algorithm" attack and how do you prevent it?
    3. Your JWT payload is 8KB. What problems does this cause and how do you reduce it?
  </Accordion>

  <Accordion title="When would you prefer sessions over JWT?">
    Use sessions when:

    * The app is monolithic and server-rendered (like an Express + EJS app)
    * You need easy session invalidation (e.g., logout all sessions)
    * You store user-specific state in the backend

    ## Example (session-based login):

    ```javascript theme={null}
    import session from 'express-session';

    app.use(session({
      secret: 'keyboard cat',
      resave: false,
      saveUninitialized: true,
      cookie: { secure: false },
    }));
    ```

    ## Why:

    Sessions allow you to track user data server-side and revoke tokens instantly.

    ## When:

    In traditional web apps or dashboards.

    ## Where:

    Stored in Redis for scalability.
  </Accordion>

  <Accordion title="How do you protect routes and implement Role-Based Access Control (RBAC)?">
    RBAC ensures only specific roles can perform actions.

    ## Example:

    ```javascript theme={null}
    function authorizeRole(...roles) {
      return (req, res, next) => {
        if (!roles.includes(req.user.role)) {
          return res.status(403).json({ error: 'Access denied' });
        }
        next();
      };
    }

    // Usage
    app.delete('/users/:id', verifyToken, authorizeRole('admin'), deleteUser);
    ```

    ## Why:

    Prevents unauthorized operations from lower-privileged users.

    ## When:

    In systems with hierarchical roles (admin, manager, user).

    ## Where:

    Middleware layer.
  </Accordion>

  <Accordion title="What is the difference between RBAC and ABAC?">
    | Concept     | RBAC                      | ABAC                           |
    | ----------- | ------------------------- | ------------------------------ |
    | Full form   | Role-Based Access Control | Attribute-Based Access Control |
    | Based on    | User role                 | User + Resource attributes     |
    | Flexibility | Static                    | Dynamic (context-aware)        |

    ## Example (ABAC):

    ```javascript theme={null}
    // Only allow if user owns the resource
    if (req.user.id !== post.authorId) {
      return res.status(403).json({ error: 'Not allowed' });
    }
    ```

    ## Why:

    ABAC allows more granular control.

    ## When:

    Use ABAC in enterprise apps needing dynamic policies (like file sharing).

    ## Where:

    Applied at business logic level.
  </Accordion>

  <Accordion title="How do you securely store passwords in Node.js?">
    Never store plain text passwords — always hash and salt them.

    ## Example using bcrypt:

    ```javascript theme={null}
    import bcrypt from 'bcrypt';

    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(password, salt);
    ```

    ## Why:

    Hashing protects passwords even if the database is compromised.

    ## When:

    During user registration or password change.

    ## Where:

    Inside your user service layer before saving to DB.
  </Accordion>

  <Accordion title="How would you implement refresh tokens with JWT?">
    Access tokens expire quickly (e.g., 15m). Refresh tokens generate new access tokens securely.

    ## Example:

    ```javascript theme={null}
    // Generate both
    const accessToken = jwt.sign({ userId }, JWT_SECRET, { expiresIn: '15m' });
    const refreshToken = jwt.sign({ userId }, REFRESH_SECRET, { expiresIn: '7d' });

    // Refresh endpoint
    app.post('/refresh', (req, res) => {
      const { token } = req.body;
      const user = jwt.verify(token, REFRESH_SECRET);
      const newAccessToken = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '15m' });
      res.json({ accessToken: newAccessToken });
    });
    ```

    ## Why:

    Improves security while maintaining usability.

    ## When:

    For long-lived sessions (like mobile apps).

    ## Where:

    Store refresh tokens in DB or secure cookies.
  </Accordion>

  <Accordion title="How do you handle token revocation (logout) in JWT-based systems?">
    Since JWTs are stateless, you can't just "delete" them.

    ## Common strategies:

    1. Blacklist tokens in Redis
    2. Rotate refresh tokens (invalidate old ones)
    3. Use short expiry times for access tokens

    ## Example:

    ```javascript theme={null}
    // Blacklist token on logout
    redisClient.setex(token, expiryTime, 'blacklisted');
    ```

    ## Why:

    Prevents reuse of stolen tokens.

    ## When:

    During logout or detected suspicious activity.

    ## Where:

    Store in Redis for quick lookup.
  </Accordion>

  <Accordion title="What are common security vulnerabilities in authentication systems?">
    1. JWT token leakage — store tokens securely
    2. No HTTPS — exposes credentials
    3. Brute force attacks — use rate limiting
    4. Insecure password reset links — use short-lived tokens

    ## Example mitigation:

    ```javascript theme={null}
    import rateLimit from 'express-rate-limit';
    app.use('/auth/login', rateLimit({ windowMs: 15 * 60 * 1000, max: 5 }));
    ```

    ## Why:

    Authentication is a top security target.

    ## When:

    Apply protections globally.

    ## Where:

    Security middleware layer.
  </Accordion>

  <Accordion title="How would you integrate social logins like Google or Facebook?">
    Use OAuth 2.0 and libraries like passport.js.

    ## Example:

    ```javascript theme={null}
    import passport from 'passport';
    import { Strategy as GoogleStrategy } from 'passport-google-oauth20';

    passport.use(new GoogleStrategy({
      clientID: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET,
      callbackURL: '/auth/google/callback',
    }, (accessToken, refreshToken, profile, done) => {
      done(null, profile);
    }));
    ```

    ## Why:

    Simplifies user onboarding.

    ## When:

    In consumer apps (like e-commerce or SaaS).

    ## Where:

    Handled by auth microservice or route handler.
  </Accordion>
</AccordionGroup>

<hr />

## 5. React Fundamentals & Core Concepts

<AccordionGroup>
  <Accordion title="Beginner Level - React Fundamentals">
    <AccordionGroup>
      <Accordion title="What is React?">
        React is a **JavaScript library** (not a framework) for building user interfaces through composable, reusable components. The key word is "library" -- React handles the **view layer only** and deliberately does not include routing, state management, or data fetching (unlike Angular which is a full framework).

        **Core concepts that define React:**

        * **Component-based architecture** -- UIs are built from self-contained components that manage their own state and compose together. Think of LEGO blocks
        * **Virtual DOM** -- React maintains a lightweight in-memory representation of the real DOM. When state changes, React diffs the old and new virtual trees and applies only the minimal necessary changes to the real DOM (reconciliation)
        * **One-way data flow** -- data flows down from parent to child via props. Children communicate up via callback props. This makes data flow predictable and debuggable
        * **Declarative rendering** -- you describe *what* the UI should look like for a given state, and React figures out *how* to update the DOM. You never write `document.getElementById().innerHTML = ...`

        **What most people miss:** React's real innovation was not the Virtual DOM (which is actually slower than targeted manual DOM updates). It was making UI development **predictable** by treating rendering as a pure function of state: `UI = f(state)`. This mental model is what makes large applications manageable.

        **What interviewers are really testing:** Whether you understand React's philosophy (declarative, compositional, unidirectional) or just its features.

        **Red flag answer:** "React is a framework for building websites." It is a library (no opinions on routing/state/HTTP), and it builds UIs, not just websites (React Native, React Three Fiber, etc.).

        **Follow-up:**

        1. What is the difference between a library and a framework? Why does this distinction matter for React?
        2. If the Virtual DOM adds overhead (diffing), why does React use it instead of direct DOM manipulation?
        3. How does React's one-way data flow compare to Angular's two-way data binding? What are the trade-offs?
      </Accordion>

      <Accordion title="Explain JSX">
        JSX is a **syntax extension for JavaScript** that lets you write HTML-like markup inside JS files. It is not HTML -- it is syntactic sugar that Babel/SWC transpiles to `React.createElement()` calls (or the new JSX transform in React 17+ which does not need `React` in scope).

        **What JSX compiles to:**

        ```jsx theme={null}
        // You write:
        const element = <h1 className="title">Hello</h1>;

        // Babel compiles to:
        const element = React.createElement("h1", { className: "title" }, "Hello");
        ```

        **Key differences from HTML:**

        * `class` becomes `className` (because `class` is a reserved word in JS)
        * `for` becomes `htmlFor`
        * All tags must be closed (`<img />`, `<br />`)
        * Style is an object: `style={{ color: "red", fontSize: "16px" }}`
        * Curly braces `{}` embed any JavaScript expression: `<p>{user.name}</p>`
        * You cannot use `if/else` directly in JSX -- use ternary or logical AND: `{isLoggedIn ? <Dashboard /> : <Login />}`

        **Why JSX exists (the controversial history):** When React launched in 2013, mixing HTML in JavaScript was considered a terrible idea. The prevailing wisdom was strict separation of concerns (HTML, CSS, JS in separate files). React's argument: the real unit of concern is a *component*, not a file type. A button's markup, behavior, and styling are inherently coupled.

        **What interviewers are really testing:** Whether you understand that JSX is an abstraction over `createElement` calls and can reason about its limitations.

        **Red flag answer:** "JSX is HTML inside JavaScript." It is not HTML -- it is a JS expression that produces React elements. This distinction matters for understanding rendering.

        **Follow-up:**

        1. Can you use React without JSX? When would you want to?
        2. What happens if you return two sibling elements from a component without a wrapper? How do Fragments solve this?
        3. Why does JSX require a single root element?
      </Accordion>

      <Accordion title="What are components?">
        Components are **self-contained, reusable building blocks** that encapsulate UI, behavior, and (optionally) state. Every React application is a tree of components, from the root `App` down to the smallest `Button`.

        **Functional components (the standard since React 16.8):**

        ```jsx theme={null}
        function UserCard({ name, email, onEdit }) {
          return (
            <div className="card">
              <h2>{name}</h2>
              <p>{email}</p>
              <button onClick={onEdit}>Edit</button>
            </div>
          );
        }
        ```

        **Key principles for good components:**

        * **Single responsibility** -- a component should do one thing well. If a component needs 500 lines, split it
        * **Props are the interface** -- components receive data and callbacks via props (read-only inputs)
        * **State is internal** -- components manage their own dynamic data with `useState`/`useReducer`
        * **Composition over inheritance** -- React strongly favors composing components together rather than class inheritance. Use `children` prop, render props, or custom hooks

        **Component naming rules:**

        * Must start with an uppercase letter (`UserCard`, not `userCard`) -- lowercase is interpreted as HTML tags
        * By convention, one component per file, named the same as the file

        **What interviewers are really testing:** Whether you can design clean, reusable component APIs and understand the composition model.

        **Red flag answer:** "Components are functions that return HTML." They return React elements (not HTML), and the interesting part is how you design their prop interfaces and compose them.

        **Follow-up:**

        1. How do you decide when to split a component into smaller components?
        2. What is the difference between a "presentational" component and a "container" component? Is this pattern still relevant with hooks?
        3. How do you make a component truly reusable across different projects?
      </Accordion>

      <Accordion title="What are props?">
        Props (short for "properties") are **read-only inputs** that flow from parent to child components. They are React's mechanism for passing data down the component tree and are the foundation of React's one-way data flow.

        **Key rules:**

        * Props are **immutable** in the child -- never modify `props.name` directly
        * Props can be **any JavaScript value**: strings, numbers, objects, arrays, functions, even other components
        * **Default props** can be set with destructuring: `function Button({ variant = "primary" })`
        * **Children** is a special prop: `<Card><p>Hello</p></Card>` -- the `<p>` is available as `props.children`

        **Callback props for upward communication:**

        ```jsx theme={null}
        function Parent() {
          const [name, setName] = useState("");
          return <ChildInput onChange={setName} />;
        }

        function ChildInput({ onChange }) {
          return <input onChange={(e) => onChange(e.target.value)} />;
        }
        ```

        **TypeScript props (production standard):**

        ```tsx theme={null}
        interface UserCardProps {
          name: string;
          email: string;
          isAdmin?: boolean; // optional
          onDelete: (id: string) => void;
        }

        function UserCard({ name, email, isAdmin = false, onDelete }: UserCardProps) {
          // ...
        }
        ```

        **What interviewers are really testing:** Whether you understand one-way data flow and can design clean prop interfaces, not just pass data.

        **Red flag answer:** "Props are like function arguments." Technically correct but misses the immutability constraint, callback patterns, and children prop.

        **Follow-up:**

        1. What happens if you try to mutate a prop inside a child component?
        2. How do you avoid "prop drilling" when you need to pass data through 5+ levels of components?
        3. What is the difference between passing a callback via props vs using `useContext` for communication?
      </Accordion>

      <Accordion title="What is state?">
        State is a component's **private, mutable data** that, when changed, triggers a re-render. If props are inputs to a component, state is the component's internal memory.

        **Core rules:**

        * State is **local and encapsulated** -- no other component can read or modify it directly
        * State updates are **asynchronous and batched** -- calling `setState` does not immediately change the value
        * **Never mutate state directly** -- `state.count++` will not trigger a re-render. Always use the setter: `setCount(count + 1)`
        * For updates based on previous state, use the **functional form**: `setCount(prev => prev + 1)` -- this avoids stale closure bugs

        **When to use state vs derived values:**

        ```jsx theme={null}
        // BAD: storing derived state
        const [items, setItems] = useState([]);
        const [filteredItems, setFilteredItems] = useState([]); // redundant!

        // GOOD: derive from existing state
        const [items, setItems] = useState([]);
        const [filter, setFilter] = useState("");
        const filteredItems = items.filter(item => item.name.includes(filter));
        ```

        **The "single source of truth" principle:** Every piece of data should have exactly one owner. If two components need the same state, lift it up to their common parent rather than duplicating it.

        **What interviewers are really testing:** Whether you understand when to use state, when to derive values, and the immutability rules. Candidates who over-use state (storing derived values, duplicating data) reveal weak React understanding.

        **Red flag answer:** "State is a variable that triggers re-render." Misses immutability, async batching, functional updates, and the principle of minimal state.

        **Follow-up:**

        1. You have 10 pieces of data in a form. Should you use 10 separate `useState` calls or one `useState` with an object? What are the trade-offs?
        2. Why does React not allow direct state mutation? What would happen if it did?
        3. When should you use `useReducer` instead of `useState`?
      </Accordion>

      <Accordion title="What is the difference between render and re-render in React?">
        **Render** is when React executes your component function and creates the Virtual DOM tree. **Re-render** happens when React needs to update the component due to state or props changes.

        ## Initial Render (Mount Phase):

        When a component is first added to the UI:

        * React calls your component function (App(), Button(), etc.)
        * Returns JSX (or React.createElement)
        * React builds a virtual DOM tree
        * It renders to the real DOM
        * Triggers effects like `useEffect(() => {}, [])`

        ## Re-render (Update Phase):

        A re-render happens when:

        * `useState` change: `setCount(1)`
        * `useReducer` dispatch: `dispatch({ type: 'ADD' })`
        * Props from parent change
        * Context value update

        ## What happens during re-render:

        1. React re-invokes the component function
        2. Gets new JSX
        3. Builds a new virtual DOM
        4. Diffs it with the previous one (using a diffing algorithm)
        5. Updates only the changed elements in the real DOM — improving performance

        That's called **reconciliation**.

        <Info>
          Understanding render vs re-render is crucial for optimizing React applications and debugging performance issues.
        </Info>
      </Accordion>

      <Accordion title="How does useState work under the hood?">
        When you call `useState`, React:

        1. Creates an internal memory slot (in the Fiber node)
        2. Stores the initialValue there
        3. Returns two things:
           * The current value from memory
           * A setState function that schedules a re-render

        ## React Internally Stores Hooks Like an Array:

        ```jsx theme={null}
        function Component() {
          const [a] = useState(1); // hooks[0]
          const [b] = useState(2);  // hooks[1]
        }
        ```

        Internally it tracks like: `hooks = [1, 2]`

        <Warning>
          That's why you can't call hooks inside if/else or loops — React must know the order of hooks each render.
        </Warning>
      </Accordion>

      <Accordion title="Does setState replace or merge the value in useState?">
        `useState` **replaces** the value entirely, unlike class components (`this.setState`) which merge.

        ## Example:

        ```jsx theme={null}
        const [user, setUser] = useState({ name: 'John', age: 25 });
        setUser({ name: 'Doe' }); // ❌ age is gone!
        ```

        ## To preserve previous values:

        ```jsx theme={null}
        setUser(prev => ({ ...prev, name: 'Doe' })); // ✅ preserves age
        ```

        <Note>
          Always use the functional update form when updating based on previous state.
        </Note>
      </Accordion>

      <Accordion title="Is setState synchronous or asynchronous?">
        `setState` is **asynchronous**. React schedules the state update, and the new state is applied on the next render.

        ## Example:

        ```jsx theme={null}
        setCount(1);
        console.log(count); // ❌ still shows previous value
        ```

        ## To get the latest value:

        ```jsx theme={null}
        setCount(prev => {
          console.log(prev); // ✅ logs updated value
          return prev + 1;
        });
        ```

        <Info>
          Use `useEffect` or the functional update form to work with the latest state value.
        </Info>
      </Accordion>

      <Accordion title="What are common pitfalls when using useState?">
        | Mistake                                            | Why it breaks                        |
        | -------------------------------------------------- | ------------------------------------ |
        | Calling `useState` conditionally                   | Breaks hook ordering                 |
        | Not copying old state in object/array updates      | You'll lose previous data            |
        | Setting state and expecting it to update instantly | Updates are asynchronous and batched |

        ## Example of state update pitfall:

        ```jsx theme={null}
        // ❌ Wrong - loses previous state
        const [user, setUser] = useState({ name: 'John', age: 25 });
        setUser({ name: 'Doe' });

        // ✅ Correct - preserves previous state
        setUser(prev => ({ ...prev, name: 'Doe' }));
        ```
      </Accordion>

      <Accordion title="What are real-world use cases for useState?">
        Common use cases include:

        * Form inputs: `useState("")`
        * Toggling modal open/close: `useState(false)`
        * Page tabs: `useState("home")`
        * Simple UI flags (loading, error): `useState(false)`

        ## Example:

        ```jsx theme={null}
        function LoginForm() {
          const [email, setEmail] = useState("");
          const [password, setPassword] = useState("");
          const [isLoading, setIsLoading] = useState(false);

          return (
            <form>
              <input 
                value={email} 
                onChange={(e) => setEmail(e.target.value)} 
              />
              <input 
                type="password"
                value={password} 
                onChange={(e) => setPassword(e.target.value)} 
              />
              <button disabled={isLoading}>
                {isLoading ? "Loading..." : "Login"}
              </button>
            </form>
          );
        }
        ```
      </Accordion>

      <Accordion title="What is useEffect and when does it run?">
        `useEffect` is a side effect hook that allows your code to run after the component renders.

        A side effect in React is anything that:

        * Reaches outside the component (e.g., fetch, timer, localStorage)
        * Doesn't directly involve rendering JSX

        ## Basic Syntax:

        ```jsx theme={null}
        useEffect(() => {
          // side effect here (e.g., API call, event listener)
          return () => {
            // cleanup (optional)
          };
        }, [dependencies]);
        ```

        ## Breakdown by Dependency Array:

        ### 1. No array = Run on every render:

        ```jsx theme={null}
        useEffect(() => {
          console.log("Runs on every render");
        });
        ```

        ### 2. Empty array = Run once (like componentDidMount):

        ```jsx theme={null}
        useEffect(() => {
          console.log("Runs once after mount");
        }, []);
        ```

        ### 3. With dependencies = Run when values change:

        ```jsx theme={null}
        useEffect(() => {
          console.log("Runs when user changes", user);
        }, [user]);
        ```
      </Accordion>

      <Accordion title="How does useEffect cleanup function work?">
        The cleanup function is your replacement for `componentWillUnmount`. It runs:

        * Before running the effect again (on updates)
        * When the component unmounts

        ## Example:

        ```jsx theme={null}
        useEffect(() => {
          const timer = setInterval(() => console.log('Tick'), 1000);
          
          return () => {
            clearInterval(timer); // Cleanup on unmount or re-run
          };
        }, []);
        ```

        ## Real Example - Logging Scroll Position:

        ```jsx theme={null}
        function Logger() {
          useEffect(() => {
            const logScroll = () => console.log(window.scrollY);
            window.addEventListener('scroll', logScroll);

            // Cleanup
            return () => {
              window.removeEventListener('scroll', logScroll);
            };
          }, []); // empty array = run once
        }
        ```

        <Warning>
          Always clean up subscriptions, timers, and event listeners to prevent memory leaks.
        </Warning>
      </Accordion>

      <Accordion title="How does useEffect map to class component lifecycle methods?">
        | Lifecycle            | useEffect Equivalent              |
        | -------------------- | --------------------------------- |
        | componentDidMount    | `useEffect(() => {...}, [])`      |
        | componentDidUpdate   | `useEffect(() => {...}, [dep])`   |
        | componentWillUnmount | Cleanup function inside useEffect |

        ## Example:

        ```jsx theme={null}
        // Class Component
        class Example extends React.Component {
          componentDidMount() {
            console.log("Mounted");
          }
          componentDidUpdate(prevProps) {
            if (prevProps.user !== this.props.user) {
              console.log("User changed");
            }
          }
          componentWillUnmount() {
            console.log("Unmounting");
          }
        }

        // Functional Component with useEffect
        function Example({ user }) {
          useEffect(() => {
            console.log("Mounted");
            return () => console.log("Unmounting");
          }, []);

          useEffect(() => {
            console.log("User changed", user);
          }, [user]);
        }
        ```
      </Accordion>

      <Accordion title="Why does useEffect run after the component renders?">
        `useEffect` runs **after** the component renders because:

        1. React first renders the component to the DOM
        2. Then it runs side effects (like API calls, subscriptions)
        3. This ensures the UI is visible immediately, and side effects don't block rendering

        <Info>
          If you need to run code before the browser paints, use `useLayoutEffect` instead.
        </Info>
      </Accordion>

      <Accordion title="What happens if you don't provide a key in a list?">
        Without a unique key, React cannot properly identify which items changed, were added, or removed — leading to:

        * Unnecessary re-renders
        * Incorrect UI updates

        ## Code Example:

        ```jsx theme={null}
        function ListExample({ items }) {
          return (
            <ul>
              {items.map((item) => (
                // Always provide a unique key!
                <li key={item.id}>{item.name}</li>
              ))}
            </ul>
          );
        }
        ```

        ## Bad Example (causes re-render issues):

        ```jsx theme={null}
        <li key={index}>{item.name}</li>
        ```

        <Warning>
          If the list order changes, items may be mismatched when using index as key.
        </Warning>
      </Accordion>

      <Accordion title="How does state lifting work and why is it needed?">
        When multiple child components need to share or sync state, the state is "lifted up" to their common parent. This makes one source of truth for shared data.

        ## Code Example:

        ```jsx theme={null}
        function Parent() {
          const [value, setValue] = useState("");

          return (
            <>
              <ChildInput value={value} setValue={setValue} />
              <DisplayValue value={value} />
            </>
          );
        }

        function ChildInput({ value, setValue }) {
          return <input value={value} onChange={(e) => setValue(e.target.value)} />;
        }

        function DisplayValue({ value }) {
          return <p>You typed: {value}</p>;
        }
        ```

        ## Why it's important:

        Prevents inconsistent state across components.
      </Accordion>

      <Accordion title="Explain the difference between props drilling and context API. When would you use each?">
        * **Props Drilling**: Passing props manually through multiple nested components
        * **Context API**: Allows data to be shared globally without passing props at every level

        ## Props Drilling Example:

        ```jsx theme={null}
        function GrandParent() {
          const theme = "dark";
          return <Parent theme={theme} />;
        }

        function Parent({ theme }) {
          return <Child theme={theme} />;
        }

        function Child({ theme }) {
          return <p>Theme is {theme}</p>;
        }
        ```

        ## Context API Example:

        ```jsx theme={null}
        import { createContext, useContext } from "react";

        const ThemeContext = createContext("light");

        function GrandParent() {
          return (
            <ThemeContext.Provider value="dark">
              <Child />
            </ThemeContext.Provider>
          );
        }

        function Child() {
          const theme = useContext(ThemeContext);
          return <p>Theme is {theme}</p>;
        }
        ```

        ## When to use Context:

        When data (like theme, user, locale) is needed globally or deeply nested.
      </Accordion>

      <Accordion title="Explain the Virtual DOM and how React uses it to optimize rendering">
        The Virtual DOM (VDOM) is a lightweight copy of the real DOM that React keeps in memory. When a component's state or props change:

        * React creates a new virtual DOM tree
        * It diffs it with the previous one (using a diffing algorithm)
        * It updates only the changed elements in the real DOM — improving performance

        ## Code Example:

        ```jsx theme={null}
        import React, { useState } from "react";

        export default function Counter() {
          const [count, setCount] = useState(0);

          // React updates only the <p> element, not the entire DOM
          return (
            <div>
              <h1>Virtual DOM Example</h1>
              <p>Count: {count}</p>
              <button onClick={() => setCount(count + 1)}>Increment</button>
            </div>
          );
        }
        ```

        ## Why it matters:

        Directly updating the DOM is expensive because each change can trigger layout recalculation, repaint, and reflow. The Virtual DOM batches changes and applies them in a single DOM operation.

        **What most candidates get wrong:** The Virtual DOM is not faster than manual, targeted DOM manipulation. What it does is make **declarative programming** fast enough. Without it, you would need to manually track which DOM nodes changed -- which is error-prone and scales poorly for complex UIs. The VDOM trades a small performance overhead for a massive improvement in developer experience and code maintainability.

        **The Reconciliation Algorithm (the "diffing"):**

        * React compares elements at the **same tree level** (O(n) complexity, not O(n^3))
        * If the element type changes (`<div>` to `<span>`), React destroys the old subtree and rebuilds
        * If the type is the same, React only updates the changed attributes
        * **Keys** help React identify which list items changed, were added, or removed

        **What interviewers are really testing:** Whether you understand the trade-offs of the VDOM approach and can explain reconciliation, or just repeat "Virtual DOM is fast."

        **Red flag answer:** "The Virtual DOM makes React faster than vanilla JavaScript." This is technically incorrect -- it makes React fast enough while being declarative.

        **Follow-up:**

        1. Svelte compiles away the Virtual DOM entirely. What is the argument for and against React's VDOM approach?
        2. How do React's `key` props affect the reconciliation algorithm? What happens with unstable keys?
        3. What is the difference between the "render phase" and the "commit phase" in React's rendering pipeline?
      </Accordion>

      <Accordion title="Difference between Controlled and Uncontrolled Components">
        * **Controlled Component**: React controls the input's value using state
        * **Uncontrolled Component**: The DOM handles the input's value directly via ref

        ## Code Example (Controlled):

        ```jsx theme={null}
        import { useState } from "react";

        function ControlledInput() {
          const [value, setValue] = useState("");

          return (
            <input
              value={value}
              onChange={(e) => setValue(e.target.value)}
              placeholder="Controlled"
            />
          );
        }
        ```

        ## Code Example (Uncontrolled):

        ```jsx theme={null}
        import { useRef } from "react";

        function UncontrolledInput() {
          const inputRef = useRef();

          const handleSubmit = () => {
            alert(inputRef.current.value);
          };

          return (
            <>
              <input ref={inputRef} placeholder="Uncontrolled" />
              <button onClick={handleSubmit}>Submit</button>
            </>
          );
        }
        ```

        <Note>
          Controlled is best for validation or dynamic UI; uncontrolled can be used for performance or simple forms.
        </Note>
      </Accordion>

      <Accordion title="What are React Hooks? Can you explain how useEffect works with dependencies?">
        Hooks are special functions that let you use React features (state, lifecycle, context, etc.) in function components.

        * `useEffect` allows you to perform side effects (like data fetching, DOM updates, event listeners)
        * The dependency array controls when the effect runs

        ## Code Example:

        ```jsx theme={null}
        import { useEffect, useState } from "react";

        function FetchUser() {
          const [user, setUser] = useState(null);

          useEffect(() => {
            fetch("https://jsonplaceholder.typicode.com/users/1")
              .then((res) => res.json())
              .then(setUser);
          }, []); // runs once after component mounts

          return <p>{user ? user.name : "Loading..."}</p>;
        }
        ```

        ## Behavior based on dependencies:

        * `[]` → runs once (on mount)
        * `[var]` → runs when var changes
        * no array → runs on every render
      </Accordion>

      <Accordion title="What are custom hooks and when do you create one?">
        Custom Hooks allow you to reuse logic between components. You create one when multiple components share the same logic (e.g., fetching, resizing, authentication).

        ## Code Example:

        ```jsx theme={null}
        import { useState, useEffect } from "react";

        function useFetch(url) {
          const [data, setData] = useState(null);

          useEffect(() => {
            fetch(url)
              .then((res) => res.json())
              .then(setData);
          }, [url]);

          return data;
        }

        // Usage
        function User() {
          const user = useFetch("https://jsonplaceholder.typicode.com/users/1");
          return <p>{user ? user.name : "Loading..."}</p>;
        }
        ```

        ## When to use:

        When you want to abstract and share reusable React logic without duplicating code.
      </Accordion>
    </AccordionGroup>
  </Accordion>

  <Accordion title="Intermediate Level - Advanced Hooks & Optimization">
    <AccordionGroup>
      <Accordion title="What is automatic batching in React 18?">
        In React 18, **automatic batching** means that all state updates—no matter where they happen (events, timeouts, async functions)—are grouped into a single re-render.

        ## Difference from Earlier Versions:

        * **React 17 and earlier**: Only updates in React event handlers were batched
        * **React 18**: All updates are batched automatically, even in async code

        ## Example:

        ```jsx theme={null}
        function DataFetcher() {
          const [isLoading, setIsLoading] = useState(false);
          const [data, setData] = useState(null);

          const fetchData = async () => {
            setIsLoading(true);        // Update 1
            const result = await fetch('/api/data');
            const json = await result.json();
            setData(json);             // Update 2
            setIsLoading(false);       // Update 3
          };
        }
        ```

        ## What Happens in React 18:

        All 3 updates (`setIsLoading(true)`, `setData()`, and `setIsLoading(false)`) are batched together, and the component re-renders only **once**.

        <Info>
          This reduces unnecessary re-renders and makes your app faster, especially when fetching data from APIs or using setTimeout/Promises.
        </Info>
      </Accordion>

      <Accordion title="What is event handler batching in React?">
        Event handler batching means React groups multiple state updates made inside the same event handler (like a button click or input change) into a single re-render.

        * ✅ This helps avoid multiple re-renders for each individual state update
        * ✅ It's built-in and works in both class and functional components
        * ✅ This behavior has existed in React even before version 18

        ## Real-Life Example:

        ```jsx theme={null}
        function Form() {
          const [name, setName] = useState("");
          const [email, setEmail] = useState("");

          const handleSubmit = () => {
            setName('John Doe');           // 1st update
            setEmail('john@example.com');  // 2nd update
            // React batches these - only one re-render!
          };

          return (
            <div>
              <input 
                value={name} 
                onChange={(e) => setName(e.target.value)} 
              />
              <input 
                value={email} 
                onChange={(e) => setEmail(e.target.value)} 
              />
              <button onClick={handleSubmit}>Submit</button>
            </div>
          );
        }
        ```

        <Info>
          When `handleSubmit` runs, React batches the two state updates, and the component re-renders only once, not twice. This makes the UI faster and avoids flicker or lag.
        </Info>
      </Accordion>

      <Accordion title="What is flushSync() and when should you use it?">
        `flushSync()` is a special React method that tells React to apply state updates **immediately**—not later, not in the next render cycle, but right now.

        Normally, React waits and batches updates to make rendering more efficient. But sometimes, you need the UI to update right away—synchronously.

        ## Example:

        ```jsx theme={null}
        import { useState } from 'react';
        import { flushSync } from 'react-dom';

        function Counter() {
          const [count, setCount] = useState(0);

          const handleIncrement = () => {
            flushSync(() => {
              setCount(count + 1); // force this update to be applied right away
            });
            console.log('Count after flushSync:', count); // logs updated count
          };

          return <button onClick={handleIncrement}>Increment</button>;
        }
        ```

        ## When to Use:

        * **Testing**: When writing tests, you want to ensure all updates are done before checking the result
        * **Real-time UI**: In collaborative editors or games where instant feedback is critical
        * **Third-party libraries**: When working with libraries that depend on real-time DOM updates

        <Warning>
          Use it sparingly—React delays updates on purpose to improve performance. Only force sync updates when truly needed.
        </Warning>
      </Accordion>

      <Accordion title="How do React.memo, useMemo, and useCallback help optimize re-renders?">
        These help optimize unnecessary re-renders by caching:

        * **React.memo** → skips re-rendering if props haven't changed
        * **useMemo** → skips recalculating expensive values
        * **useCallback** → skips recreating identical function references

        <Note>
          These do **not** prevent re-renders — they help avoid **unnecessary** re-renders.
        </Note>

        ## Example with React.memo:

        ```jsx theme={null}
        const Child = React.memo(({ name }) => {
          console.log("Child rendered");
          return <p>{name}</p>;
        });

        function Parent() {
          const [count, setCount] = useState(0);
          return (
            <>
              <p>Count: {count}</p>
              <Child name="John" /> {/* Won't re-render when count changes */}
              <button onClick={() => setCount(c => c + 1)}>Increment</button>
            </>
          );
        }
        ```

        ## Example with useMemo:

        ```jsx theme={null}
        function ExpensiveComponent({ items }) {
          const expensiveValue = useMemo(() => {
            return items.reduce((sum, item) => sum + item.value, 0);
          }, [items]);

          return <div>Total: {expensiveValue}</div>;
        }
        ```

        ## Example with useCallback:

        ```jsx theme={null}
        const Child = React.memo(({ onClick }) => {
          return <button onClick={onClick}>Click</button>;
        });

        function Parent() {
          const [count, setCount] = useState(0);
          const increment = useCallback(() => setCount(c => c + 1), []);

          return <Child onClick={increment} />;
        }
        ```
      </Accordion>

      <Accordion title="What happens during a re-render with useEffect cleanup?">
        During a re-render with `useEffect`:

        1. React re-executes the component function
        2. Compares old + new Virtual DOM
        3. Decides what to update in the real DOM (reconciliation)
        4. **Cleanup function runs** (if dependencies changed or component unmounts)
        5. New effect runs after the updated DOM is committed

        ## Real Example:

        ```jsx theme={null}
        function Counter() {
          const [count, setCount] = useState(0);

          useEffect(() => {
            console.log("Effect runs");
            return () => {
              console.log("Cleanup runs");
            };
          }, [count]);

          return (
            <div>
              <p>{count}</p>
              <button onClick={() => setCount(count + 1)}>Increment</button>
            </div>
          );
        }
        ```

        ## On First Render:

        * `count` is 0
        * Renders JSX
        * Prints: "Effect runs"

        ## Click Button → Re-render:

        * `setCount(1)` triggers re-render
        * JSX re-evaluated
        * **Cleanup prints**: "Cleanup runs"
        * **Then new effect prints**: "Effect runs"
      </Accordion>

      <Accordion title="How do you handle component re-renders and optimize performance?">
        Use memoization and avoid unnecessary renders:

        * `React.memo()` → prevents re-render if props haven't changed
        * `useMemo()` → memoizes values
        * `useCallback()` → memoizes functions
        * Avoid anonymous functions inside render if possible

        ## Code Example:

        ```jsx theme={null}
        import React, { useState, useCallback, memo } from "react";

        const Child = memo(({ onClick }) => {
          console.log("Child rendered");
          return <button onClick={onClick}>Click</button>;
        });

        function Parent() {
          const [count, setCount] = useState(0);
          const increment = useCallback(() => setCount((c) => c + 1), []);

          return (
            <>
              <p>Count: {count}</p>
              <Child onClick={increment} />
            </>
          );
        }
        ```

        ## Result:

        Child won't re-render unnecessarily because onClick reference stays stable.
      </Accordion>

      <Accordion title="Explain the differences between useMemo() and useCallback() in React.">
        Both are optimization hooks, but they serve different purposes:

        | Hook          | Purpose                | Returns                         |
        | ------------- | ---------------------- | ------------------------------- |
        | `useMemo`     | Memoizes **values**    | The memoized value              |
        | `useCallback` | Memoizes **functions** | The memoized function reference |

        ## useMemo Example:

        ```jsx theme={null}
        function ExpensiveComponent({ items }) {
          // Recalculates only when items change
          const total = useMemo(() => {
            return items.reduce((sum, item) => sum + item.price, 0);
          }, [items]);

          return <div>Total: ${total}</div>;
        }
        ```

        ## useCallback Example:

        ```jsx theme={null}
        function Parent() {
          const [count, setCount] = useState(0);
          
          // Function reference stays stable
          const handleClick = useCallback(() => {
            setCount(c => c + 1);
          }, []);

          return <Child onClick={handleClick} />;
        }
        ```

        <Warning>
          Don't overuse these hooks. They have their own overhead. Only use when you have performance issues.
        </Warning>
      </Accordion>

      <Accordion title="How would you implement a search feature with debouncing in React?">
        Debouncing delays the execution of a function until after a specified time has passed.

        ## Example:

        ```jsx theme={null}
        function SearchComponent() {
          const [query, setQuery] = useState('');
          const [results, setResults] = useState([]);

          useEffect(() => {
            if (!query) {
              setResults([]);
              return;
            }

            const timer = setTimeout(() => {
              // Perform search
              fetch(`/api/search?q=${query}`)
                .then(r => r.json())
                .then(setResults);
            }, 500); // Wait 500ms after user stops typing

            return () => clearTimeout(timer);
          }, [query]);

          return (
            <div>
              <input
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Search..."
              />
              <ul>
                {results.map(item => <li key={item.id}>{item.name}</li>)}
              </ul>
            </div>
          );
        }
        ```

        ## Custom Hook Version:

        ```jsx theme={null}
        function useDebounce(value, delay) {
          const [debouncedValue, setDebouncedValue] = useState(value);

          useEffect(() => {
            const handler = setTimeout(() => {
              setDebouncedValue(value);
            }, delay);

            return () => clearTimeout(handler);
          }, [value, delay]);

          return debouncedValue;
        }

        // Usage
        const debouncedQuery = useDebounce(query, 500);
        useEffect(() => {
          if (debouncedQuery) {
            fetchResults(debouncedQuery);
          }
        }, [debouncedQuery]);
        ```

        <Info>
          Debouncing reduces API calls and improves performance by waiting for the user to finish typing.
        </Info>
      </Accordion>

      <Accordion title="How would you re-render a component when the window is resized?">
        Use `useEffect` with a resize event listener:

        ## Example:

        ```jsx theme={null}
        function ResponsiveComponent() {
          const [windowSize, setWindowSize] = useState({
            width: window.innerWidth,
            height: window.innerHeight
          });

          useEffect(() => {
            const handleResize = () => {
              setWindowSize({
                width: window.innerWidth,
                height: window.innerHeight
              });
            };

            window.addEventListener('resize', handleResize);
            return () => window.removeEventListener('resize', handleResize);
          }, []);

          return <div>Window: {windowSize.width} x {windowSize.height}</div>;
        }
        ```

        ## Custom Hook Version:

        ```jsx theme={null}
        function useWindowSize() {
          const [size, setSize] = useState({
            width: window.innerWidth,
            height: window.innerHeight
          });

          useEffect(() => {
            const handleResize = () => {
              setSize({
                width: window.innerWidth,
                height: window.innerHeight
              });
            };
            window.addEventListener('resize', handleResize);
            return () => window.removeEventListener('resize', handleResize);
          }, []);

          return size;
        }

        // Usage
        function Component() {
          const { width, height } = useWindowSize();
          return <div>{width} x {height}</div>;
        }
        ```
      </Accordion>

      <Accordion title="How do you handle asynchronous operations in React using async/await or Promises?">
        Handling async operations in React:

        ## In useEffect:

        ```jsx theme={null}
        useEffect(() => {
          async function fetchData() {
            const data = await fetch('/api/data').then(r => r.json());
            setData(data);
          }
          fetchData();
        }, []);
        ```

        ## In Event Handlers:

        ```jsx theme={null}
        const handleSubmit = async (e) => {
          e.preventDefault();
          try {
            const response = await fetch('/api/submit', {
              method: 'POST',
              body: JSON.stringify(formData)
            });
            const result = await response.json();
            console.log('Success:', result);
          } catch (error) {
            console.error('Error:', error);
          }
        };
        ```

        ## With Promises:

        ```jsx theme={null}
        useEffect(() => {
          fetch('/api/data')
            .then(response => response.json())
            .then(data => setData(data))
            .catch(error => setError(error));
        }, []);
        ```

        <Warning>
          You cannot make the useEffect callback itself async. Always define an async function inside useEffect and call it.
        </Warning>
      </Accordion>

      <Accordion title="Explain the use case of useEffect() for fetching data from an API.">
        `useEffect` is commonly used for data fetching because it runs after render and can handle async operations.

        ## Example:

        ```jsx theme={null}
        function UserProfile({ userId }) {
          const [user, setUser] = useState(null);
          const [loading, setLoading] = useState(true);
          const [error, setError] = useState(null);

          useEffect(() => {
            async function fetchUser() {
              try {
                setLoading(true);
                const response = await fetch(`/api/users/${userId}`);
                const data = await response.json();
                setUser(data);
              } catch (err) {
                setError(err.message);
              } finally {
                setLoading(false);
              }
            }

            fetchUser();
          }, [userId]); // Re-fetch when userId changes

          if (loading) return <p>Loading...</p>;
          if (error) return <p>Error: {error}</p>;
          return <div>{user?.name}</div>;
        }
        ```

        <Info>
          For better data fetching, consider React Query or SWR which handle caching, refetching, and error states automatically.
        </Info>
      </Accordion>

      <Accordion title="How do you handle errors in a React app, and what is the role of error boundaries?">
        Error boundaries catch JavaScript errors in the component tree and display fallback UI.

        ## Error Boundary Example:

        ```jsx theme={null}
        class ErrorBoundary extends React.Component {
          state = { hasError: false };

          static getDerivedStateFromError(error) {
            return { hasError: true };
          }

          componentDidCatch(error, errorInfo) {
            console.error('Error caught:', error, errorInfo);
            // Log to error reporting service
          }

          render() {
            if (this.state.hasError) {
              return <h2>Something went wrong.</h2>;
            }
            return this.props.children;
          }
        }

        // Usage
        <ErrorBoundary>
          <MyComponent />
        </ErrorBoundary>
        ```

        ## Important Notes:

        * Error boundaries only catch errors in **children components**
        * They don't catch errors in event handlers, async code, or during SSR
        * Use multiple error boundaries for granular error handling

        <Warning>
          Error boundaries must be class components. Functional components cannot be error boundaries (yet).
        </Warning>
      </Accordion>

      <Accordion title="How would you implement dynamic form handling and validation in React?">
        Dynamic form handling with validation:

        ## Example:

        ```jsx theme={null}
        function DynamicForm() {
          const [formData, setFormData] = useState({});
          const [errors, setErrors] = useState({});

          const handleChange = (name, value) => {
            setFormData(prev => ({ ...prev, [name]: value }));
            // Clear error when user types
            if (errors[name]) {
              setErrors(prev => ({ ...prev, [name]: '' }));
            }
          };

          const validate = () => {
            const newErrors = {};
            if (!formData.email) newErrors.email = 'Email required';
            if (!formData.email?.includes('@')) newErrors.email = 'Invalid email';
            setErrors(newErrors);
            return Object.keys(newErrors).length === 0;
          };

          const handleSubmit = (e) => {
            e.preventDefault();
            if (validate()) {
              console.log('Form valid:', formData);
            }
          };

          return (
            <form onSubmit={handleSubmit}>
              <input
                value={formData.email || ''}
                onChange={(e) => handleChange('email', e.target.value)}
              />
              {errors.email && <span>{errors.email}</span>}
              <button type="submit">Submit</button>
            </form>
          );
        }
        ```

        <Info>
          For complex forms, consider libraries like React Hook Form or Formik for better validation and performance.
        </Info>
      </Accordion>

      <Accordion title="What is lazy loading in React, and how does it improve application performance?">
        Lazy loading defers loading components until they're needed, reducing initial bundle size.

        ## How it works:

        * Components are split into separate chunks
        * Loaded only when required (route navigation, conditional rendering)
        * Reduces initial JavaScript bundle size

        ## Example:

        ```jsx theme={null}
        import { lazy, Suspense } from 'react';

        // Lazy load the component
        const Dashboard = lazy(() => import('./Dashboard'));
        const Settings = lazy(() => import('./Settings'));

        function App() {
          return (
            <Suspense fallback={<div>Loading...</div>}>
              <Dashboard />
            </Suspense>
          );
        }
        ```

        ## Benefits:

        * **Faster Initial Load**: Smaller initial bundle
        * **Better Performance**: Load code on demand
        * **Improved User Experience**: Faster time to interactive

        <Info>
          In Next.js, code splitting is automatic per page. Use `React.lazy()` for manual code splitting in regular React apps.
        </Info>
      </Accordion>

      <Accordion title="Describe how React Context API can be used for state management in an app.">
        Context API provides a way to share data across the component tree without prop drilling.

        ## Example:

        ```jsx theme={null}
        // Create Context
        const ThemeContext = createContext();

        // Provider Component
        function App() {
          const [theme, setTheme] = useState('light');
          return (
            <ThemeContext.Provider value={{ theme, setTheme }}>
              <Header />
              <Content />
            </ThemeContext.Provider>
          );
        }

        // Consumer Component
        function Header() {
          const { theme, setTheme } = useContext(ThemeContext);
          return (
            <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
              Current: {theme}
            </button>
          );
        }
        ```

        ## When to Use:

        * Global state like theme, user, language
        * Avoiding prop drilling through many levels
        * Simple state that doesn't need complex logic

        <Warning>
          Context causes all consumers to re-render when value changes. Split contexts or use memoization for performance.
        </Warning>
      </Accordion>

      <Accordion title="What is the role of React Router, and how does it work with dynamic routing?">
        React Router enables client-side routing in single-page applications.

        ## Basic Setup:

        ```jsx theme={null}
        import { BrowserRouter, Routes, Route } from 'react-router-dom';

        function App() {
          return (
            <BrowserRouter>
              <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/about" element={<About />} />
                <Route path="/users/:id" element={<UserProfile />} />
              </Routes>
            </BrowserRouter>
          );
        }
        ```

        ## Dynamic Routing:

        ```jsx theme={null}
        import { useParams } from 'react-router-dom';

        function UserProfile() {
          const { id } = useParams(); // Gets :id from URL
          return <div>User ID: {id}</div>;
        }
        ```

        ## Navigation:

        ```jsx theme={null}
        import { useNavigate, Link } from 'react-router-dom';

        function Navigation() {
          const navigate = useNavigate();
          return (
            <>
              <Link to="/about">About</Link>
              <button onClick={() => navigate('/users/123')}>
                Go to User
              </button>
            </>
          );
        }
        ```

        <Info>
          React Router enables SPA navigation without full page reloads, improving user experience.
        </Info>
      </Accordion>

      <Accordion title="How would you pass data between sibling components in React without using Redux?">
        Methods to pass data between siblings without Redux:

        1. **Lift State Up**: Move shared state to common parent
        2. **Context API**: Share data through React Context
        3. **Event Emitters**: Use custom event system
        4. **State Management Libraries**: Zustand, Jotai (lighter than Redux)

        ## Example - Lifting State:

        ```jsx theme={null}
        function Parent() {
          const [sharedData, setSharedData] = useState('');
          return (
            <>
              <SiblingA data={sharedData} setData={setSharedData} />
              <SiblingB data={sharedData} />
            </>
          );
        }
        ```

        ## Example - Context API:

        ```jsx theme={null}
        const DataContext = createContext();

        function Parent() {
          const [data, setData] = useState('');
          return (
            <DataContext.Provider value={{ data, setData }}>
              <SiblingA />
              <SiblingB />
            </DataContext.Provider>
          );
        }

        function SiblingA() {
          const { setData } = useContext(DataContext);
          return <input onChange={(e) => setData(e.target.value)} />;
        }
        ```
      </Accordion>
    </AccordionGroup>
  </Accordion>

  <Accordion title="Advanced Level - Expert Questions">
    <AccordionGroup>
      <Accordion title="What are the limitations of React in building large-scale applications?">
        React has several limitations when building large-scale applications:

        * **State Management Complexity**: As apps grow, prop drilling and state management become complex without additional libraries (Redux, Zustand)
        * **Bundle Size**: React itself adds to bundle size, and without code splitting, initial load can be slow
        * **SEO Challenges**: Client-side rendering can hurt SEO without SSR (Next.js helps)
        * **Performance with Large Lists**: Rendering thousands of items can be slow without virtualization
        * **No Built-in Routing**: Requires additional libraries (React Router)
        * **Learning Curve**: JSX, hooks, and patterns require significant learning
        * **Debugging Complexity**: Large component trees can be hard to debug

        <Info>
          These limitations are often addressed with ecosystem tools like Next.js, Redux, React Router, and virtualization libraries.
        </Info>
      </Accordion>

      <Accordion title="How does React manage the Virtual DOM, and what are the benefits?">
        React manages the Virtual DOM by:

        1. **Creating a Virtual Representation**: React creates a lightweight JavaScript object representation of the DOM
        2. **Diffing Algorithm**: When state changes, React creates a new Virtual DOM tree and compares it with the previous one
        3. **Reconciliation**: React determines the minimal set of changes needed
        4. **Batch Updates**: React batches DOM updates for efficiency
        5. **Commit Phase**: React applies only the necessary changes to the real DOM

        ## Benefits:

        * **Performance**: Avoids expensive direct DOM manipulation
        * **Efficiency**: Only updates what changed, not entire trees
        * **Predictability**: Makes UI updates more predictable and easier to reason about
        * **Cross-browser Compatibility**: Abstracts browser differences

        <Info>
          The Virtual DOM is React's core optimization strategy that makes it fast even with complex UIs.
        </Info>
      </Accordion>

      <Accordion title="Can React Hooks fully replace Redux for state management? Explain why or why not.">
        React Hooks (useState, useContext, useReducer) can replace Redux in many cases, but not always.

        ## When Hooks are Sufficient:

        * Small to medium applications
        * Simple state that doesn't need time-travel debugging
        * Local component state or shared state via Context
        * No need for middleware (logging, async actions)

        ## When Redux is Better:

        * Large applications with complex state
        * Need for time-travel debugging
        * Middleware requirements (Redux Thunk, Saga)
        * Predictable state updates with strict patterns
        * DevTools for debugging

        ## Example with useReducer (Redux-like):

        ```jsx theme={null}
        const initialState = { count: 0 };

        function 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, initialState);
          return (
            <div>
              <p>{state.count}</p>
              <button onClick={() => dispatch({ type: 'increment' })}>+</button>
            </div>
          );
        }
        ```

        <Note>
          For most apps, Context + useReducer can replace Redux. Use Redux when you need its ecosystem and tooling.
        </Note>
      </Accordion>

      <Accordion title="What are the best practices for managing state in large React applications?">
        Best practices for state management in large React applications:

        1. **Lift State Appropriately**: Keep state as local as possible, lift only when needed
        2. **Use Context for Global State**: For theme, user, locale that many components need
        3. **Consider State Management Libraries**: Redux, Zustand, or Jotai for complex state
        4. **Separate Server and Client State**: Use React Query or SWR for server state
        5. **Normalize State Shape**: Keep state flat and normalized (like Redux)
        6. **Use Custom Hooks**: Abstract state logic into reusable hooks
        7. **Avoid Prop Drilling**: Use Context or state management for deeply nested props

        ## Example Structure:

        ```jsx theme={null}
        // Local state (component level)
        const [isOpen, setIsOpen] = useState(false);

        // Shared state (Context)
        const { user, setUser } = useContext(UserContext);

        // Server state (React Query)
        const { data } = useQuery(['users'], fetchUsers);

        // Global state (Zustand)
        const { count, increment } = useStore();
        ```
      </Accordion>

      <Accordion title="How would you optimize performance in a React app with large component trees?">
        Optimization strategies for large component trees:

        1. **Code Splitting**: Use `React.lazy()` and `Suspense` to split code
        2. **Memoization**: Use `React.memo()`, `useMemo()`, `useCallback()`
        3. **Virtualization**: Use `react-window` or `react-virtualized` for long lists
        4. **Avoid Inline Functions**: Move functions outside render or use `useCallback`
        5. **Proper Keys**: Use stable, unique keys in lists
        6. **State Colocation**: Keep state close to where it's used
        7. **React.memo with Custom Comparison**: For expensive components

        ## Example:

        ```jsx theme={null}
        // Code splitting
        const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

        // Virtualization
        import { FixedSizeList } from 'react-window';
        <FixedSizeList height={600} itemCount={1000} itemSize={35}>
          {Row}
        </FixedSizeList>

        // Memoization
        const ExpensiveChild = React.memo(Child, (prev, next) => {
          return prev.id === next.id;
        });
        ```
      </Accordion>

      <Accordion title="Explain React's Strict Mode and its impact on development.">
        React Strict Mode is a development tool that helps identify potential problems in your application.

        ## What it does:

        * **Double Invokes**: Intentionally double-invokes functions to detect side effects
        * **Deprecation Warnings**: Warns about deprecated APIs
        * **Unsafe Lifecycle Warnings**: Identifies unsafe lifecycle methods
        * **Legacy String Ref Warnings**: Warns about string refs

        ## Example:

        ```jsx theme={null}
        import { StrictMode } from 'react';

        function App() {
          return (
            <StrictMode>
              <MyComponent />
            </StrictMode>
          );
        }
        ```

        ## Impact:

        * Helps catch bugs early in development
        * Ensures components are resilient to re-mounting
        * Prepares for future React features
        * **Note**: Strict Mode only runs in development, not production

        <Info>
          Strict Mode helps ensure your code is ready for concurrent features and future React versions.
        </Info>
      </Accordion>

      <Accordion title="How can you prevent unnecessary re-renders in React functional components?">
        Strategies to prevent unnecessary re-renders:

        1. **React.memo()**: Wrap components to prevent re-renders if props haven't changed
        2. **useMemo()**: Memoize expensive calculations
        3. **useCallback()**: Memoize function references
        4. **State Colocation**: Move state down to the component that needs it
        5. **Split Components**: Break large components into smaller ones
        6. **Avoid Creating Objects in Render**: Move object/array creation outside render

        ## Example:

        ```jsx theme={null}
        // ❌ Bad - creates new object every render
        function Parent() {
          const [count, setCount] = useState(0);
          return <Child config={{ theme: 'dark' }} />;
        }

        // ✅ Good - stable reference
        const config = { theme: 'dark' };
        function Parent() {
          const [count, setCount] = useState(0);
          return <Child config={config} />;
        }

        // ✅ Better - useMemo
        function Parent() {
          const [count, setCount] = useState(0);
          const config = useMemo(() => ({ theme: 'dark' }), []);
          return <Child config={config} />;
        }
        ```
      </Accordion>

      <Accordion title="Describe the key differences between functional and class components in React.">
        | Aspect         | Functional Components | Class Components          |
        | -------------- | --------------------- | ------------------------- |
        | Syntax         | Function declaration  | Class extends Component   |
        | State          | `useState` hook       | `this.state`              |
        | Lifecycle      | `useEffect` hook      | `componentDidMount`, etc. |
        | Performance    | Generally faster      | Slightly more overhead    |
        | Code Size      | Less code             | More boilerplate          |
        | Hooks          | ✅ Can use all hooks   | ❌ Cannot use hooks        |
        | `this` binding | Not needed            | Required for methods      |

        ## Example Comparison:

        ```jsx theme={null}
        // Functional Component
        function Counter() {
          const [count, setCount] = useState(0);
          useEffect(() => console.log('Mounted'), []);
          return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
        }

        // Class Component
        class Counter extends React.Component {
          state = { count: 0 };
          componentDidMount() { console.log('Mounted'); }
          render() {
            return <button onClick={() => this.setState({ count: this.state.count + 1 })}>
              {this.state.count}
            </button>;
          }
        }
        ```

        <Info>
          Functional components are now the recommended approach. Class components are maintained for legacy code.
        </Info>
      </Accordion>

      <Accordion title="What is the significance of the React Fiber architecture?">
        React Fiber is a **complete rewrite of React's core reconciliation algorithm** (shipped in React 16). The old "stack reconciler" processed the entire component tree synchronously -- once it started rendering, it could not stop until the entire tree was processed. For complex UIs, this caused dropped frames and janky interactions.

        **What Fiber changes:**

        * **Work units (Fibers)**: Each component instance becomes a "fiber" -- a JavaScript object that represents a unit of work. React can process these units one at a time, yielding to the browser between them
        * **Interruptible rendering**: React can pause rendering mid-tree, handle a high-priority update (like a user click), and then resume where it left off. The old reconciler could not do this
        * **Priority-based scheduling**: User interactions (typing, clicking) get higher priority than background updates (data fetching, analytics). This is what powers `useTransition` and `useDeferredValue` in React 18

        **Fiber node structure (simplified):**
        Each fiber contains: `type` (component function/class), `key`, `child` (first child fiber), `sibling` (next sibling fiber), `return` (parent fiber), `pendingProps`, `memoizedState`, `effectTag` (what DOM operation to perform).

        **Concrete features Fiber enables:**

        * **Concurrent Mode / Concurrent Features** (React 18) -- rendering can be interrupted
        * **Suspense** -- pause rendering while waiting for async data
        * **Automatic batching** -- group multiple state updates into one render
        * **Transitions** (`useTransition`) -- mark non-urgent updates so they do not block user input
        * **Error boundaries** -- handle errors at the fiber level without crashing the entire tree

        **The two-phase rendering:**

        * **Render phase** (interruptible): React walks the fiber tree, computing what changed. No side effects. Can be paused/restarted
        * **Commit phase** (synchronous): React applies all changes to the DOM in one batch. Cannot be interrupted

        **What interviewers are really testing:** Whether you understand the architectural shift from synchronous to interruptible rendering and can connect Fiber to concrete features like Suspense and transitions.

        **Red flag answer:** "Fiber makes React faster." Fiber is not about raw speed -- it is about **responsiveness**. Rendering the same tree takes roughly the same time, but the UI stays interactive during heavy renders.

        **Follow-up:**

        1. How does `useTransition` use Fiber's priority system to keep input fields responsive during expensive state updates?
        2. What is the difference between the "render phase" and "commit phase" in terms of what can and cannot be interrupted?
        3. Why does React warn against side effects during render? How does Fiber's interruptible rendering make side effects in render especially dangerous?
      </Accordion>

      <Accordion title="How does React handle side effects, and how can you manage them effectively?">
        React handles side effects through the `useEffect` hook, which runs after render.

        ## Effective Management:

        1. **Separate Concerns**: Use multiple `useEffect` hooks for different side effects
        2. **Proper Dependencies**: Always include all dependencies in the dependency array
        3. **Cleanup**: Always clean up subscriptions, timers, and event listeners
        4. **Avoid Infinite Loops**: Be careful with dependencies that change on every render

        ## Example:

        ```jsx theme={null}
        function UserProfile({ userId }) {
          const [user, setUser] = useState(null);
          const [posts, setPosts] = useState([]);

          // Separate effects for different concerns
          useEffect(() => {
            fetchUser(userId).then(setUser);
          }, [userId]);

          useEffect(() => {
            fetchPosts(userId).then(setPosts);
          }, [userId]);

          // Cleanup example
          useEffect(() => {
            const interval = setInterval(() => console.log('Tick'), 1000);
            return () => clearInterval(interval);
          }, []);

          return <div>{user?.name}</div>;
        }
        ```
      </Accordion>

      <Accordion title="How would you implement custom hooks to abstract logic in React?">
        Custom hooks are functions that start with "use" and can call other hooks.

        ## Example - useFetch:

        ```jsx theme={null}
        function useFetch(url) {
          const [data, setData] = useState(null);
          const [loading, setLoading] = useState(true);
          const [error, setError] = useState(null);

          useEffect(() => {
            fetch(url)
              .then(r => r.json())
              .then(setData)
              .catch(setError)
              .finally(() => setLoading(false));
          }, [url]);

          return { data, loading, error };
        }

        // Usage
        function UserProfile({ userId }) {
          const { data: user, loading, error } = useFetch(`/api/users/${userId}`);
          if (loading) return <p>Loading...</p>;
          if (error) return <p>Error: {error.message}</p>;
          return <div>{user.name}</div>;
        }
        ```

        ## Example - useLocalStorage:

        ```jsx theme={null}
        function useLocalStorage(key, initialValue) {
          const [storedValue, setStoredValue] = useState(() => {
            try {
              const item = window.localStorage.getItem(key);
              return item ? JSON.parse(item) : initialValue;
            } catch (error) {
              return initialValue;
            }
          });

          const setValue = (value) => {
            try {
              setStoredValue(value);
              window.localStorage.setItem(key, JSON.stringify(value));
            } catch (error) {
              console.error(error);
            }
          };

          return [storedValue, setValue];
        }
        ```

        <Info>
          Custom hooks enable code reuse and logic abstraction across components.
        </Info>
      </Accordion>

      <Accordion title="Explain useRef and when you would use it instead of useState">
        `useRef` creates a **mutable reference** that persists across re-renders but, crucially, **does not trigger a re-render when changed**. This makes it fundamentally different from `useState`.

        **Three primary use cases:**

        **1. Accessing DOM elements directly:**

        ```jsx theme={null}
        function TextInput() {
          const inputRef = useRef(null);

          const focusInput = () => inputRef.current.focus();

          return (
            <>
              <input ref={inputRef} />
              <button onClick={focusInput}>Focus Input</button>
            </>
          );
        }
        ```

        **2. Storing mutable values that should not trigger re-renders:**

        ```jsx theme={null}
        function Timer() {
          const intervalRef = useRef(null);
          const [seconds, setSeconds] = useState(0);

          const start = () => {
            intervalRef.current = setInterval(() => {
              setSeconds(s => s + 1);
            }, 1000);
          };

          const stop = () => clearInterval(intervalRef.current);

          return <div>{seconds}s <button onClick={start}>Start</button></div>;
        }
        ```

        **3. Tracking previous values:**

        ```jsx theme={null}
        function usePrevious(value) {
          const ref = useRef();
          useEffect(() => { ref.current = value; });
          return ref.current;
        }
        ```

        **Key distinction from useState:**

        | Aspect                       | useState                  | useRef                                                |
        | ---------------------------- | ------------------------- | ----------------------------------------------------- |
        | Triggers re-render on change | Yes                       | No                                                    |
        | Persists across renders      | Yes                       | Yes                                                   |
        | Mutable directly             | No (use setter)           | Yes (`ref.current = x`)                               |
        | Best for                     | UI state (what user sees) | Internal state (timer IDs, DOM refs, previous values) |

        **What interviewers are really testing:** Whether you know that not every piece of mutable data needs to be state. Using `useState` for timer IDs or render counts causes unnecessary re-renders.

        **Red flag answer:** "useRef is for accessing DOM elements." That is one use case, but missing the mutable-value-without-re-render use case shows shallow understanding.

        **Follow-up:**

        1. Why does storing a timer ID in `useState` vs `useRef` cause different behavior? Which is correct?
        2. How does `useRef` avoid the stale closure problem that `useState` can have in callbacks?
        3. What is `useImperativeHandle` and when would you pair it with `forwardRef`?
      </Accordion>

      <Accordion title="What are Higher-Order Components (HOCs) and when would you use them?">
        HOCs are functions that take a component and return a new component with added functionality. They are the function composition pattern applied to React components: `EnhancedComponent = higherOrderComponent(WrappedComponent)`.

        **The key insight:** HOCs do not modify the input component. They **wrap** it, creating a new component that renders the original with additional props or behavior.

        ## Example:

        ```jsx theme={null}
        // withAuth.js -- adds auth checking to any component
        const withAuth = (WrappedComponent) => {
          return function AuthenticatedComponent(props) {
            const isAuthenticated = Boolean(localStorage.getItem("token"));
            if (!isAuthenticated) {
              return <p>Please login first</p>;
            }
            return <WrappedComponent {...props} />;
          };
        };

        // Usage -- Dashboard now requires auth without changing its code
        const Dashboard = () => <h2>Welcome to Dashboard</h2>;
        export default withAuth(Dashboard);
        ```

        **Why HOCs are less common now:** Custom hooks solve the same problem (sharing logic) with less indirection. A `useAuth()` hook is simpler than `withAuth(Component)`. However, HOCs are still valid for:

        * **Cross-cutting concerns that need to wrap rendering** (error boundaries, layout wrappers)
        * **Third-party library integration** (React-Redux's `connect()` is a HOC)
        * **When you need to intercept or modify rendering**, not just add data

        **Common pitfalls:**

        * HOCs lose the original component's static methods -- use `hoist-non-react-statics` to copy them
        * Refs do not pass through -- use `React.forwardRef` to forward refs
        * Too many HOCs create "wrapper hell": `withAuth(withTheme(withRouter(Component)))` -- this is why hooks won

        **What interviewers are really testing:** Whether you understand the evolution from HOCs to hooks and can articulate trade-offs between the patterns.

        **Red flag answer:** "HOCs are outdated, just use hooks." They are less common but not obsolete -- understanding both shows pattern literacy.

        **Follow-up:**

        1. How would you refactor a HOC into a custom hook? What changes and what does not?
        2. What is the "wrapper hell" problem with HOCs and how do hooks solve it?
        3. Can you compose multiple HOCs? What problems arise from deep HOC nesting?
      </Accordion>

      <Accordion title="What is the Render Props pattern?">
        Render Props is a technique where a component accepts a **function as a prop** and uses it to determine what to render. The component provides data or behavior, and the render function decides the UI. It inverts the control of rendering.

        ## Example:

        ```jsx theme={null}
        function MouseTracker({ render }) {
          const [pos, setPos] = React.useState({ x: 0, y: 0 });
          return (
            <div onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>
              {render(pos)}
            </div>
          );
        }

        // Usage -- the consumer decides how to display the mouse position
        <MouseTracker render={({ x, y }) => <p>Mouse at {x}, {y}</p>} />
        ```

        **The evolution of code sharing patterns in React:**

        | Era   | Pattern      | Pros                           | Cons                             |
        | ----- | ------------ | ------------------------------ | -------------------------------- |
        | 2015  | Mixins       | Simple                         | Naming conflicts, tight coupling |
        | 2016  | HOCs         | Composable                     | Wrapper hell, prop conflicts     |
        | 2017  | Render Props | Explicit data flow             | Callback nesting, less readable  |
        | 2019+ | Custom Hooks | Clean, composable, no wrappers | Requires hooks rules knowledge   |

        **When render props are still useful:** For libraries that need to give consumers complete control over rendering (e.g., Downshift, React Table v7, Formik's `<Field>` component).

        **What interviewers are really testing:** Pattern evolution knowledge. They want to see you can trace the progression from mixins to hooks and explain *why* each pattern emerged.

        **Red flag answer:** "Render props are for passing functions as props." Technically true but misses the purpose: decoupling logic from presentation.

        **Follow-up:**

        1. How would you convert a render props component into a custom hook?
        2. What is the performance concern with inline render prop functions, and how do you mitigate it?
        3. The `children` prop can also be used as a render prop (`<Mouse>{pos => ...}</Mouse>`). When would you use `children` vs a named render prop?
      </Accordion>

      <Accordion title="What are the benefits of server-side rendering (SSR) in React applications?">
        Benefits of SSR in React:

        1. **SEO**: Search engines can crawl fully rendered HTML
        2. **Faster Initial Load**: Users see content immediately
        3. **Better Performance**: Reduces client-side JavaScript execution
        4. **Social Sharing**: Proper meta tags for social media previews
        5. **Accessibility**: Works better with screen readers on initial load

        ## SSR vs CSR:

        | Aspect              | SSR            | CSR         |
        | ------------------- | -------------- | ----------- |
        | Initial HTML        | Fully rendered | Empty shell |
        | SEO                 | ✅ Excellent    | ❌ Poor      |
        | Time to First Byte  | Slower         | Faster      |
        | Time to Interactive | Faster         | Slower      |

        <Info>
          Next.js provides excellent SSR support with features like `getServerSideProps` and Server Components.
        </Info>
      </Accordion>

      <Accordion title="How do you handle styling in React components? Discuss different approaches.">
        Common styling approaches in React:

        1. **CSS Modules**: Scoped CSS files
        2. **Styled Components**: CSS-in-JS library
        3. **Tailwind CSS**: Utility-first CSS framework
        4. **Inline Styles**: JavaScript objects
        5. **CSS-in-JS**: Libraries like Emotion, styled-components

        ## Example - CSS Modules:

        ```jsx theme={null}
        // Button.module.css
        .button { background: blue; }

        // Button.jsx
        import styles from './Button.module.css';
        <button className={styles.button}>Click</button>
        ```

        ## Example - Styled Components:

        ```jsx theme={null}
        import styled from 'styled-components';
        const Button = styled.button`
          background: blue;
          color: white;
        `;
        <Button>Click</Button>
        ```

        ## Example - Tailwind:

        ```jsx theme={null}
        <button className="bg-blue-500 text-white px-4 py-2">
          Click
        </button>
        ```

        <Info>
          Choose based on your project needs: CSS Modules for simplicity, Tailwind for rapid development, styled-components for dynamic styling.
        </Info>
      </Accordion>

      <Accordion title="How would you optimize React app performance when handling large lists or grids?">
        Optimization strategies for large lists:

        1. **Virtualization**: Only render visible items
        2. **Pagination**: Load items in chunks
        3. **Memoization**: Memoize list items
        4. **Proper Keys**: Use stable, unique keys

        ## Example with react-window:

        ```jsx theme={null}
        import { FixedSizeList } from 'react-window';

        function LargeList({ items }) {
          const Row = ({ index, style }) => (
            <div style={style}>
              {items[index].name}
            </div>
          );

          return (
            <FixedSizeList
              height={600}
              itemCount={items.length}
              itemSize={35}
              width="100%"
            >
              {Row}
            </FixedSizeList>
          );
        }
        ```

        ## Example with Pagination:

        ```jsx theme={null}
        function PaginatedList() {
          const [page, setPage] = useState(1);
          const itemsPerPage = 20;
          const start = (page - 1) * itemsPerPage;
          const paginatedItems = items.slice(start, start + itemsPerPage);

          return (
            <>
              {paginatedItems.map(item => <Item key={item.id} data={item} />)}
              <button onClick={() => setPage(p => p + 1)}>Next</button>
            </>
          );
        }
        ```

        <Info>
          Virtualization is the best approach for very large lists (1000+ items) as it only renders visible items.
        </Info>
      </Accordion>

      <Accordion title="Explain the difference between shallow and deep comparison in React's shouldComponentUpdate.">
        **Shallow Comparison**: Compares object references, not nested values
        **Deep Comparison**: Recursively compares all nested properties

        ## Shallow Comparison (React.memo default):

        ```jsx theme={null}
        const prev = { user: { name: 'John' } };
        const next = { user: { name: 'John' } };
        // Shallow: false (different object references)
        // Deep: true (same values)
        ```

        ## Custom Comparison:

        ```jsx theme={null}
        const UserCard = React.memo(({ user }) => {
          return <div>{user.name}</div>;
        }, (prevProps, nextProps) => {
          // Custom shallow comparison
          return prevProps.user.id === nextProps.user.id;
        });
        ```

        <Info>
          React uses shallow comparison by default for performance. Deep comparison is expensive and rarely needed.
        </Info>
      </Accordion>

      <Accordion title="How do you handle asynchronous code execution and state updates in React?">
        Handling async code and state updates:

        ## Pattern 1: useEffect with async:

        ```jsx theme={null}
        useEffect(() => {
          let cancelled = false;
          async function fetchData() {
            const data = await fetch('/api/data').then(r => r.json());
            if (!cancelled) setData(data);
          }
          fetchData();
          return () => { cancelled = true; };
        }, []);
        ```

        ## Pattern 2: AbortController:

        ```jsx theme={null}
        useEffect(() => {
          const controller = new AbortController();
          fetch('/api/data', { signal: controller.signal })
            .then(r => r.json())
            .then(setData);
          return () => controller.abort();
        }, []);
        ```

        ## Pattern 3: Functional Updates:

        ```jsx theme={null}
        const handleAsyncUpdate = async () => {
          const result = await someAsyncOperation();
          setCount(prev => prev + result); // Safe with functional update
        };
        ```

        <Warning>
          Always clean up async operations to prevent state updates on unmounted components.
        </Warning>
      </Accordion>

      <Accordion title="How would you structure large React or Next.js projects?">
        A common scalable structure:

        ```
        src/
         ├── app/
         │    ├── (routes)
         │    ├── layout.tsx
         │    └── page.tsx
         ├── components/
         │    ├── ui/
         │    ├── forms/
         │    ├── layout/
         ├── hooks/
         ├── context/
         ├── lib/
         ├── services/
         ├── store/
         ├── styles/
         └── utils/
        ```

        * **Feature-based organization** helps scale
        * **Shared state or UI logic** goes to `/context` or `/hooks`
        * **Pages are lazy-loaded** in Next.js automatically
      </Accordion>

      <Accordion title="What are error boundaries and how do they work?">
        Error boundaries catch JavaScript errors in React components and show fallback UIs instead of breaking the app. They only work in class components.

        ## Example:

        ```jsx theme={null}
        class ErrorBoundary extends React.Component {
          state = { hasError: false };
          static getDerivedStateFromError() {
            return { hasError: true };
          }
          componentDidCatch(error, info) {
            console.error("Error logged:", error, info);
          }
          render() {
            if (this.state.hasError) return <h2>Something went wrong!</h2>;
            return this.props.children;
          }
        }

        // Usage
        <ErrorBoundary>
          <ComponentThatMayCrash />
        </ErrorBoundary>
        ```
      </Accordion>

      <Accordion title="Explain the concept of render optimization in React">
        To prevent unnecessary re-renders:

        * Use `React.memo()` for pure functional components
        * Use `useCallback` and `useMemo` to memoize functions and computed values
        * Avoid creating new objects/functions in render unnecessarily

        ## Example:

        ```jsx theme={null}
        const Button = React.memo(({ onClick }) => {
          console.log("Rendered Button");
          return <button onClick={onClick}>Click me</button>;
        });

        function App() {
          const handleClick = React.useCallback(() => console.log("Clicked!"), []);
          return <Button onClick={handleClick} />;
        }
        ```
      </Accordion>

      <Accordion title="What is the difference between a monolithic and modular frontend architecture?">
        | Aspect     | Monolithic                                           | Modular (Micro-frontend)                                           |
        | ---------- | ---------------------------------------------------- | ------------------------------------------------------------------ |
        | Structure  | All components tightly coupled and deployed together | App divided into independent modules (built & deployed separately) |
        | Team Size  | Better for small teams                               | Ideal for large teams, multiple domains                            |
        | Deployment | Single deployment                                    | Independent deployments                                            |
        | Tech Stack | Single technology                                    | Tech diversity (React + Vue + Angular)                             |

        ## When to use Modular:

        * Large teams, multiple domains
        * Independent deployments
        * Tech diversity requirements
      </Accordion>

      <Accordion title="How do you manage global state in large apps?">
        Options:

        * **Context API** for light global state
        * **Redux Toolkit / Zustand / Jotai** for complex or shared logic
        * **React Query** for server state

        ## Example with Zustand:

        ```jsx theme={null}
        import { create } from "zustand";

        const useStore = create((set) => ({
          count: 0,
          increase: () => set((state) => ({ count: state.count + 1 })),
        }));

        function Counter() {
          const { count, increase } = useStore();
          return <button onClick={increase}>Count: {count}</button>;
        }
        ```
      </Accordion>

      <Accordion title="Explain React's reconciliation process and how it updates the DOM efficiently.">
        Reconciliation is React's algorithm for comparing the old and new Virtual DOM trees to determine what needs to be updated.

        ## Process:

        1. **Render Phase**: React creates a new Virtual DOM tree
        2. **Diffing**: Compares new tree with previous tree
        3. **Reconciliation**: Determines minimal set of changes
        4. **Commit Phase**: Applies changes to real DOM

        ## Key Optimizations:

        * **Same-level Comparison**: React compares elements at the same level
        * **Key Optimization**: Keys help React identify which items changed
        * **Batching**: Multiple updates are batched together
        * **Fiber Architecture**: Enables incremental rendering

        ## Example:

        ```jsx theme={null}
        // Old Virtual DOM
        <div>
          <p>Hello</p>
          <span>World</span>
        </div>

        // New Virtual DOM
        <div>
          <p>Hello</p>
          <span>React</span>  // Only this changes
        </div>

        // React only updates the <span> text node, not the entire tree
        ```

        <Info>
          Reconciliation is what makes React fast - it minimizes expensive DOM operations by only updating what changed.
        </Info>
      </Accordion>
    </AccordionGroup>
  </Accordion>
</AccordionGroup>

<hr />

## 6. NEXT JS

<AccordionGroup>
  <Accordion title="Explain the difference between the Pages Router and App Router in Next.js">
    | Feature            | Pages Router (pages/)                  | App Router (app/)                  |
    | ------------------ | -------------------------------------- | ---------------------------------- |
    | Introduced         | Before Next.js 13                      | Next.js 13+                        |
    | Rendering          | CSR, SSR, SSG                          | RSC, SSR, SSG, ISR                 |
    | File-based routing | Yes                                    | Yes (with nested layouts)          |
    | Data fetching      | `getServerSideProps`, `getStaticProps` | Async components or fetch directly |
    | Layouts            | Custom                                 | Built-in persistent layouts        |
    | Server Components  | ❌                                      | ✅ Default                          |
    | Client Components  | ✅                                      | ✅ (with "use client")              |

    ## Example (App Router):

    ```jsx theme={null}
    // app/page.tsx
    export default async function HomePage() {
      const data = await fetch("https://api.example.com/posts").then(res => res.json());
      return <div>{data.map(p => <p key={p.id}>{p.title}</p>)}</div>;
    }
    ```

    ## Example (Pages Router):

    ```jsx theme={null}
    // pages/index.js
    export async function getServerSideProps() {
      const res = await fetch("https://api.example.com/posts");
      const data = await res.json();
      return { props: { data } };
    }
    export default function Home({ data }) {
      return <div>{data.map(p => <p key={p.id}>{p.title}</p>)}</div>;
    }
    ```
  </Accordion>

  <Accordion title="What are Server Components and Client Components in Next.js 13+?">
    * **Server Components (default)**:
      * Run on the server (never in browser)
      * Can fetch data directly
      * Reduce bundle size and improve performance

    * **Client Components**:
      * Run in the browser
      * Must be marked with "use client"
      * Can use useState, useEffect, event handlers, etc.

    ## Example:

    ```jsx theme={null}
    // app/page.tsx (Server Component)
    import ClientButton from "./ClientButton";

    export default async function Page() {
      const data = await fetch("https://api.example.com/user").then(r => r.json());
      return (
        <div>
          <h1>Hello, {data.name}</h1>
          <ClientButton />
        </div>
      );
    }

    // app/ClientButton.tsx (Client Component)
    "use client";
    import { useState } from "react";

    export default function ClientButton() {
      const [count, setCount] = useState(0);
      return <button onClick={() => setCount(count + 1)}>Clicked {count}</button>;
    }
    ```
  </Accordion>

  <Accordion title="How does SSR differ from SSG and ISR in Next.js?">
    | Mode                                  | Description                              | When to Use                                       |
    | ------------------------------------- | ---------------------------------------- | ------------------------------------------------- |
    | SSR (Server-Side Rendering)           | Page rendered at every request           | Dynamic data that changes often (e.g., dashboard) |
    | SSG (Static Site Generation)          | Page pre-rendered at build time          | Static content (e.g., blog, docs)                 |
    | ISR (Incremental Static Regeneration) | SSG + revalidation after a time interval | Semi-static content (e.g., news feed)             |

    ## Example (ISR):

    ```jsx theme={null}
    // app/blog/page.tsx
    export const revalidate = 60; // regenerate every 60 seconds

    export default async function BlogPage() {
      const posts = await fetch("https://api.example.com/posts").then(res => res.json());
      return <div>{posts.map(p => <p key={p.id}>{p.title}</p>)}</div>;
    }
    ```
  </Accordion>

  <Accordion title="When would you choose SSR vs CSR?">
    * **SSR**: When SEO and fast first paint are important
    * **CSR (Client-Side Rendering)**: When user-specific or highly interactive data is needed (like dashboards)

    ## Example CSR (client fetch):

    ```jsx theme={null}
    "use client";
    import { useEffect, useState } from "react";

    export default function Dashboard() {
      const [data, setData] = useState([]);

      useEffect(() => {
        fetch("/api/data").then(res => res.json()).then(setData);
      }, []);

      return <div>{data.map(item => <p key={item.id}>{item.name}</p>)}</div>;
    }
    ```
  </Accordion>

  <Accordion title="How do you handle API routes in Next.js?">
    In App Router, API routes live under `/app/api/*/route.ts`.

    ## Example:

    ```jsx theme={null}
    // app/api/user/route.ts
    import { NextResponse } from "next/server";

    export async function GET() {
      const user = { name: "Shehroze", age: 28 };
      return NextResponse.json(user);
    }

    export async function POST(req: Request) {
      const body = await req.json();
      return NextResponse.json({ message: "User created", data: body });
    }
    ```

    ## Usage:

    ```jsx theme={null}
    const res = await fetch("/api/user");
    const user = await res.json();
    ```
  </Accordion>

  <Accordion title="Explain middleware and where it runs">
    Middleware runs before a request is processed. It can:

    * Redirect or rewrite requests
    * Check authentication
    * Modify headers

    **Runs on**: Edge Runtime (very fast, lightweight)

    ## Example:

    ```jsx theme={null}
    // middleware.ts
    import { NextResponse } from "next/server";

    export function middleware(req) {
      const isLoggedIn = req.cookies.get("token");
      const url = req.nextUrl.clone();

      if (!isLoggedIn && url.pathname.startsWith("/dashboard")) {
        url.pathname = "/login";
        return NextResponse.redirect(url);
      }
    }
    ```
  </Accordion>

  <Accordion title="How does generateMetadata work in the App Router?">
    `generateMetadata()` allows dynamic SEO metadata generation per page.

    ## Example:

    ```jsx theme={null}
    // app/blog/[slug]/page.tsx
    export async function generateMetadata({ params }) {
      const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(r => r.json());
      return {
        title: post.title,
        description: post.excerpt,
      };
    }

    export default function BlogPost({ params }) {
      return <h1>Post: {params.slug}</h1>;
    }
    ```

    <Info>
      Benefit: SEO-friendly and supports dynamic OG tags, locales, etc.
    </Info>
  </Accordion>

  <Accordion title="What are Layouts and Parallel Routes in Next.js?">
    * **Layouts**: Persistent UI (e.g., navbars, sidebars) wrapping child routes
    * **Parallel Routes**: Allow rendering multiple route segments simultaneously (e.g., tabs)

    ## Layout Example:

    ```jsx theme={null}
    // app/layout.tsx
    export default function RootLayout({ children }) {
      return (
        <html>
          <body>
            <nav>Navigation</nav>
            {children}
          </body>
        </html>
      );
    }
    ```

    ## Parallel Routes Example:

    ```jsx theme={null}
    // app/@tabs/(profile)/page.tsx
    export default function ProfileTab() {
      return <p>Profile Tab</p>;
    }

    // app/@tabs/(settings)/page.tsx
    export default function SettingsTab() {
      return <p>Settings Tab</p>;
    }
    ```
  </Accordion>

  <Accordion title="How does Next.js handle Image Optimization?">
    Next.js `<Image>` component optimizes images automatically:

    * Lazy loading
    * Responsive resizing
    * WebP conversion

    ## Example:

    ```jsx theme={null}
    import Image from "next/image";

    export default function Hero() {
      return (
        <Image
          src="/hero.jpg"
          alt="Hero Banner"
          width={1200}
          height={600}
          priority
        />
      );
    }
    ```

    <Info>
      Benefit: Automatically reduces payload and improves Core Web Vitals.
    </Info>
  </Accordion>

  <Accordion title="How do you do Internationalization (i18n) in Next.js?">
    Next.js has built-in i18n support in config and route-level solutions.

    ## Example using next-intl:

    ```jsx theme={null}
    // middleware.ts
    import createMiddleware from "next-intl/middleware";

    export default createMiddleware({
      locales: ["en", "ar"],
      defaultLocale: "en",
    });
    ```

    ## Usage:

    ```jsx theme={null}
    // app/[locale]/page.tsx
    import { useTranslations } from "next-intl";

    export default function HomePage() {
      const t = useTranslations("Home");
      return <h1>{t("welcome")}</h1>;
    }
    ```

    <Check>
      Result: Automatically renders pages in the selected locale.
    </Check>
  </Accordion>

  <Accordion title="What are Server Actions in Next.js and how do they change full-stack development?">
    Server Actions are functions that run **exclusively on the server** but can be called directly from client components -- no API route needed. They are defined with the `"use server"` directive and represent a fundamental shift in how full-stack React apps handle mutations.

    ## Example -- form submission without an API route:

    ```jsx theme={null}
    // app/actions.ts
    "use server";
    import { revalidatePath } from "next/cache";

    export async function createTodo(formData: FormData) {
      const title = formData.get("title") as string;
      await db.todo.create({ data: { title } });
      revalidatePath("/todos"); // revalidate the page cache
    }

    // app/todos/page.tsx
    import { createTodo } from "../actions";

    export default function TodoPage() {
      return (
        <form action={createTodo}>
          <input name="title" placeholder="New todo" />
          <button type="submit">Add</button>
        </form>
      );
    }
    ```

    **What is happening under the hood:**

    * Next.js creates an API endpoint automatically for each Server Action
    * The client sends a POST request with the form data
    * The server executes the function and can revalidate cached pages
    * **Progressive enhancement**: forms work even without JavaScript enabled (the action attribute is a real URL)

    **When to use Server Actions vs API Routes:**

    | Use Case                          | Server Actions | API Routes                 |
    | --------------------------------- | -------------- | -------------------------- |
    | Form submissions                  | Preferred      | Works but more boilerplate |
    | Database mutations                | Preferred      | Works                      |
    | Third-party API calls from client | Not ideal      | Preferred                  |
    | Webhook endpoints                 | Cannot use     | Required                   |
    | Public API for mobile apps        | Cannot use     | Required                   |

    **Security considerations:**

    * Server Actions are effectively public API endpoints -- always validate input and authenticate the user
    * Never trust form data; use Zod or similar validation
    * Use `cookies()` or `headers()` to verify authentication inside the action

    **What interviewers are really testing:** Whether you understand the paradigm shift from "frontend calls API" to "frontend calls server function," and the security implications.

    **Red flag answer:** "Server Actions let you write backend code in frontend files." This misses that they are compiled into separate server endpoints and have specific security requirements.

    **Follow-up:**

    1. How do Server Actions handle optimistic updates in the UI? How does `useOptimistic` work with them?
    2. What happens if a Server Action throws an error? How does Next.js handle it on the client?
    3. Are Server Actions safe from CSRF attacks? How does Next.js protect them?
  </Accordion>

  <Accordion title="Explain Next.js caching layers and when to use each">
    Next.js has **four distinct caching layers**, and understanding them is critical for building performant applications. Misunderstanding caching is the #1 source of "my data is stale" bugs in Next.js apps.

    **The four caching layers:**

    | Cache               | What it caches                               | Where  | Duration                                         | Opt-out                                  |
    | ------------------- | -------------------------------------------- | ------ | ------------------------------------------------ | ---------------------------------------- |
    | Request Memoization | Duplicate `fetch()` calls in the same render | Server | Single render pass                               | Cannot opt out                           |
    | Data Cache          | `fetch()` responses                          | Server | Persistent (until revalidation)                  | `cache: "no-store"`                      |
    | Full Route Cache    | Rendered HTML and RSC payload                | Server | Persistent (until revalidation)                  | Dynamic functions or `cache: "no-store"` |
    | Router Cache        | RSC payload for visited routes               | Client | Session-based (30s for dynamic, 5min for static) | `router.refresh()`                       |

    **Common mistakes and fixes:**

    ```jsx theme={null}
    // Data is cached indefinitely by default (Data Cache)
    const data = await fetch("https://api.example.com/data");

    // Force fresh data every request
    const data = await fetch("https://api.example.com/data", {
      cache: "no-store"
    });

    // Revalidate every 60 seconds (ISR pattern)
    const data = await fetch("https://api.example.com/data", {
      next: { revalidate: 60 }
    });
    ```

    **The debugging nightmare:** If you update data via a Server Action but the page still shows old data, the problem is usually the Router Cache on the client. Call `revalidatePath("/path")` or `revalidateTag("tag")` in your Server Action.

    **What interviewers are really testing:** Whether you have actually built Next.js apps in production and debugged caching issues, or just know the theory.

    **Red flag answer:** "Next.js caches pages for performance." This is too vague -- not specifying which cache layer or how to invalidate reveals no hands-on experience.

    **Follow-up:**

    1. You updated a database record via a Server Action, but the page still shows old data. Walk through every caching layer and how you would debug this.
    2. What is the difference between `revalidatePath` and `revalidateTag`? When would you use each?
    3. How does the Router Cache interact with browser back/forward navigation?
  </Accordion>
</AccordionGroup>

<hr />

## 7. React State Management and Advanced Patterns

<AccordionGroup>
  <Accordion title="What is code splitting?">
    Code splitting is the practice of **breaking your JavaScript bundle into smaller chunks** that are loaded on demand, rather than shipping one massive file on initial page load. This directly improves Time to Interactive (TTI) and Largest Contentful Paint (LCP) -- two Core Web Vitals that Google uses for ranking.

    **How it works in React:**

    ```jsx theme={null}
    // Without code splitting: Dashboard is included in the main bundle
    import Dashboard from './Dashboard';

    // With code splitting: Dashboard is loaded only when rendered
    const Dashboard = React.lazy(() => import('./Dashboard'));

    function App() {
      return (
        <Suspense fallback={<Spinner />}>
          <Dashboard />
        </Suspense>
      );
    }
    ```

    **Route-based splitting (the most common pattern):**
    Split by route so users only download the code for the page they visit. In Next.js, this is automatic -- each page is a separate chunk.

    **Real impact:** A typical React SPA might have a 2MB bundle. Code splitting can reduce the initial load to 200-400KB, with the rest loaded on demand. At scale, this translates to measurable improvements in conversion rates -- Amazon found that every 100ms of added latency cost them 1% of sales.

    **What interviewers are really testing:** Whether you understand *when* to split, not just *how*. Over-splitting creates too many network requests; under-splitting bloats the initial bundle.

    **Red flag answer:** Mentioning `React.lazy` without discussing when and where to split, or not mentioning Suspense fallbacks.

    **Follow-up:**

    1. How do you analyze your bundle to decide where to split? What tools do you use?
    2. What happens if a lazy-loaded chunk fails to load (network error)? How do you handle it gracefully?
    3. What is the difference between code splitting and tree shaking?
  </Accordion>

  <Accordion title="Explain error boundaries">
    Error boundaries are React components that **catch JavaScript errors in their child component tree** and display a fallback UI instead of crashing the entire application. They are React's version of `try/catch` for the component tree.

    **Critical details:**

    * Error boundaries must be **class components** -- there is no hook equivalent (as of React 19). The `react-error-boundary` library provides a functional wrapper
    * They catch errors during **rendering, lifecycle methods, and constructors** of the tree below them
    * They do **NOT** catch: event handler errors, async errors (setTimeout, Promises), server-side rendering errors, or errors in the error boundary itself

    **Production pattern -- granular error boundaries:**

    ```jsx theme={null}
    // Wrap individual features, not just the entire app
    <ErrorBoundary fallback={<p>Widget failed to load</p>}>
      <StockTicker />
    </ErrorBoundary>
    <ErrorBoundary fallback={<p>Chat unavailable</p>}>
      <ChatWidget />
    </ErrorBoundary>
    ```

    This way, if the StockTicker crashes, the ChatWidget still works. Compare this with a single root error boundary that shows "Something went wrong" for the entire page.

    **What interviewers are really testing:** Whether you use error boundaries strategically (per-feature) or naively (one at the root), and whether you know their limitations.

    **Red flag answer:** "Error boundaries catch all errors." They do not catch event handler errors or async errors -- these need try/catch.

    **Follow-up:**

    1. How do you log errors caught by error boundaries to a monitoring service like Sentry?
    2. Why can error boundaries only be class components? Will this change?
    3. How do you implement a "retry" button in an error boundary to attempt re-rendering the failed component?
  </Accordion>

  <Accordion title="What are portals?">
    Portals let you render a React component's output into a **different DOM node** than its parent, while keeping it in the same React component tree. This means events still bubble up through the React tree, not the DOM tree.

    **The classic use case:**

    ```jsx theme={null}
    function Modal({ isOpen, children }) {
      if (!isOpen) return null;
      return ReactDOM.createPortal(
        <div className="modal-overlay">
          <div className="modal-content">{children}</div>
        </div>,
        document.getElementById("modal-root") // renders outside #app-root
      );
    }
    ```

    **Why portals exist:** Modals, tooltips, and dropdowns need to visually "escape" their parent container (which might have `overflow: hidden` or `z-index` stacking context issues). Without portals, a modal inside a `overflow: hidden` container would be clipped.

    **The event bubbling gotcha:** Even though the modal renders in `#modal-root` in the DOM, a click inside it will still trigger `onClick` handlers on its React parent. This is because React's synthetic event system follows the React tree, not the DOM tree. This is useful (parent can handle modal events) but can be surprising.

    **What interviewers are really testing:** Whether you understand the DOM vs React tree distinction and can explain why portals maintain React event bubbling.

    **Red flag answer:** "Portals render elements outside the parent div." This misses the key insight about event propagation.

    **Follow-up:**

    1. How does event bubbling work with portals? If a portal renders into `document.body`, does clicking inside it bubble to the React parent?
    2. How would you manage focus trapping inside a portal-based modal for accessibility?
    3. When would you use a portal vs just using CSS `position: fixed` and high `z-index`?
  </Accordion>

  <Accordion title="What is React Router?">
    React Router is the de facto **client-side routing library** for React SPAs. It intercepts browser navigation events and renders different components based on the URL path -- without a full page reload.

    **How it works under the hood:** React Router uses the browser's History API (`pushState`, `replaceState`, `popstate` event) to update the URL and trigger component re-renders. The URL becomes the "state" that determines which component tree to render.

    **Key concepts in React Router v6+:**

    * `<BrowserRouter>` -- wraps the app and provides routing context
    * `<Routes>` / `<Route>` -- defines the route-to-component mapping
    * `<Link>` / `<NavLink>` -- navigates without page reload
    * `useNavigate()` -- programmatic navigation
    * `useParams()` -- access route parameters
    * `useSearchParams()` -- access and modify query strings
    * `<Outlet>` -- renders child routes in nested layouts

    **Nested routes and layouts (the production pattern):**

    ```jsx theme={null}
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route index element={<Home />} />
        <Route path="users" element={<Users />}>
          <Route path=":id" element={<UserDetail />} />
        </Route>
      </Route>
    </Routes>
    ```

    **What interviewers are really testing:** Whether you understand nested routing, protected routes, and how routing interacts with code splitting.

    **Red flag answer:** Only showing basic `<Route path="/" element={<Home />} />` without discussing nested routes, protected routes, or lazy loading route components.

    **Follow-up:**

    1. How do you implement protected routes that redirect unauthenticated users to login?
    2. What is the difference between `BrowserRouter` and `HashRouter`? When would you use each?
    3. How does React Router interact with `React.lazy` for route-based code splitting?
  </Accordion>

  <Accordion title="Explain performance optimization">
    React performance optimization is about **preventing unnecessary work** -- unnecessary re-renders, unnecessary re-computations, and unnecessary network transfers. The key principle: measure first, optimize second. Premature optimization is a real problem in React apps.

    **The optimization hierarchy (in order of impact):**

    1. **Architecture-level** (highest impact):
       * Keep state as local as possible -- state in a top-level provider re-renders everything below it
       * Separate server state (React Query/SWR) from client state (Zustand/useState)
       * Use code splitting to reduce initial bundle size

    2. **Component-level:**
       * `React.memo()` -- skip re-rendering when props have not changed. Only useful when re-rendering is actually expensive
       * Split large components -- a component with both expensive and cheap parts should be split so the expensive part can be memoized independently
       * Use proper `key` props in lists -- wrong keys cause unnecessary DOM destruction/recreation

    3. **Computation-level:**
       * `useMemo()` -- cache expensive calculations. Do not use for cheap operations (the memoization overhead is not free)
       * `useCallback()` -- stabilize function references passed to memoized children

    4. **Rendering-level:**
       * Virtualization (`react-window`) for lists with 100+ items
       * `<Suspense>` for streaming and lazy loading
       * `useTransition` / `useDeferredValue` (React 18) for non-urgent updates

    **The rule of thumb:** If you cannot measure the performance problem with React DevTools Profiler, you probably do not need to optimize it.

    **What interviewers are really testing:** Whether you optimize strategically or reach for `useMemo` on every value. Over-memoization is a code smell.

    **Red flag answer:** "Use React.memo, useMemo, and useCallback everywhere." This shows no understanding of when optimization helps vs when it adds unnecessary complexity.

    **Follow-up:**

    1. When does `React.memo` actually hurt performance instead of helping?
    2. How do you use the React DevTools Profiler to find components that re-render too often?
    3. Your React app takes 4 seconds to become interactive on mobile. Walk me through your optimization strategy.
  </Accordion>

  <Accordion title="What's the difference between Redux, Zustand, and React Query?">
    | Library                      | Purpose                                                 | Best For                                  |
    | ---------------------------- | ------------------------------------------------------- | ----------------------------------------- |
    | Redux                        | Centralized predictable state management (global state) | Large apps needing structured data flow   |
    | Zustand                      | Lightweight state management using hooks                | Simpler state sharing without boilerplate |
    | React Query (TanStack Query) | Server-state management (fetching, caching, syncing)    | Handling API data efficiently             |

    ## Example: Redux

    ```jsx theme={null}
    // store.ts
    import { configureStore, createSlice } from "@reduxjs/toolkit";

    const counterSlice = createSlice({
      name: "counter",
      initialState: { count: 0 },
      reducers: { increment: (state) => { state.count++; } }
    });

    export const { increment } = counterSlice.actions;
    export const store = configureStore({ reducer: counterSlice.reducer });

    // Counter.tsx
    "use client";
    import { useDispatch, useSelector } from "react-redux";
    import { increment } from "./store";

    export default function Counter() {
      const dispatch = useDispatch();
      const count = useSelector((state) => state.count);
      return <button onClick={() => dispatch(increment())}>Count: {count}</button>;
    }
    ```

    ## Example: Zustand

    ```jsx theme={null}
    // useCounterStore.ts
    import { create } from "zustand";

    export const useCounterStore = create((set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }));

    // Component
    "use client";
    import { useCounterStore } from "./useCounterStore";

    export default function Counter() {
      const { count, increment } = useCounterStore();
      return <button onClick={increment}>Zustand Count: {count}</button>;
    }
    ```

    ## Example: React Query

    ```jsx theme={null}
    // app/page.tsx
    "use client";
    import { useQuery } from "@tanstack/react-query";

    export default function Users() {
      const { data, isLoading } = useQuery({
        queryKey: ["users"],
        queryFn: () => fetch("https://jsonplaceholder.typicode.com/users").then(r => r.json()),
      });

      if (isLoading) return <p>Loading...</p>;
      return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
    }
    ```

    ## Summary:

    * **Redux** → predictable, structured, global state
    * **Zustand** → minimal, fast local/global store
    * **React Query** → asynchronous data fetching & caching
  </Accordion>

  <Accordion title="How do you handle server and client data synchronization?">
    Server data is fetched and stored on load (SSR or ISR), while client data changes locally. To sync:

    1. Use React Query or SWR for automatic refetching
    2. Use mutations and invalidate queries after updates

    ## Example with React Query:

    ```jsx theme={null}
    "use client";
    import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";

    function Todos() {
      const queryClient = useQueryClient();
      const { data: todos } = useQuery(["todos"], () =>
        fetch("/api/todos").then(r => r.json())
      );

      const addTodo = useMutation({
        mutationFn: (newTodo) =>
          fetch("/api/todos", {
            method: "POST",
            body: JSON.stringify(newTodo),
          }),
        onSuccess: () => queryClient.invalidateQueries(["todos"]),
      });

      return (
        <>
          <ul>{todos?.map(t => <li key={t.id}>{t.title}</li>)}</ul>
          <button onClick={() => addTodo.mutate({ title: "New Task" })}>
            Add Todo
          </button>
        </>
      );
    }
    ```

    <Info>
      Key concept: `invalidateQueries` ensures fresh data after mutation — syncing server + client.
    </Info>
  </Accordion>

  <Accordion title="Explain how to use useReducer hook">
    `useReducer` is an alternative to `useState` for managing complex state logic.

    ## Example:

    ```jsx theme={null}
    "use client";
    import { useReducer } from "react";

    const initialState = { count: 0 };

    function reducer(state, action) {
      switch (action.type) {
        case "increment": return { count: state.count + 1 };
        case "decrement": return { count: state.count - 1 };
        default: return state;
      }
    }

    export default function Counter() {
      const [state, dispatch] = useReducer(reducer, initialState);

      return (
        <>
          <p>Count: {state.count}</p>
          <button onClick={() => dispatch({ type: "increment" })}>+</button>
          <button onClick={() => dispatch({ type: "decrement" })}>-</button>
        </>
      );
    }
    ```

    ## When to use:

    When state transitions are complex or multiple actions affect the same state.
  </Accordion>

  <Accordion title="How would you implement pagination or infinite scrolling efficiently?">
    * Use API parameters like `?page=1&limit=10`
    * Use React Query with `getNextPageParam` for infinite scroll

    ## Example:

    ```jsx theme={null}
    "use client";
    import { useInfiniteQuery } from "@tanstack/react-query";

    export default function InfiniteUsers() {
      const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
        queryKey: ["users"],
        queryFn: ({ pageParam = 1 }) =>
          fetch(`https://api.example.com/users?page=${pageParam}`).then(r => r.json()),
        getNextPageParam: (lastPage) => lastPage.nextPage ?? false,
      });

      return (
        <>
          {data?.pages.map((page, i) => (
            <div key={i}>
              {page.users.map((user) => <p key={user.id}>{user.name}</p>)}
            </div>
          ))}
          {hasNextPage && <button onClick={() => fetchNextPage()}>Load more</button>}
        </>
      );
    }
    ```

    <Info>
      Benefit: Efficient, incremental loading instead of fetching the entire dataset.
    </Info>
  </Accordion>

  <Accordion title="What is hydration and what problems can occur during hydration in Next.js?">
    * **Hydration** = The process where React on the client attaches event handlers to the already rendered HTML from the server
    * **Hydration mismatch** happens when server-rendered HTML differs from client render output

    ## Example (problematic):

    ```jsx theme={null}
    // app/page.tsx
    "use client";
    export default function Page() {
      const now = new Date().toLocaleTimeString();
      return <p>{now}</p>;
    }
    ```

    <Warning>
      Issue: Server renders one time, client renders another (time mismatch)
    </Warning>

    ## Fix:

    ```jsx theme={null}
    "use client";
    import { useEffect, useState } from "react";

    export default function Page() {
      const [time, setTime] = useState("");
      useEffect(() => setTime(new Date().toLocaleTimeString()), []);
      return <p>{time}</p>;
    }
    ```

    ## Common causes of mismatch:

    * Conditional rendering differences between server/client
    * Using `window`, `localStorage` on the server
    * Non-deterministic values during SSR
  </Accordion>

  <Accordion title="How do you handle loading and error states in data fetching?">
    Use React Suspense or manual conditional rendering.

    ## Example (React Query):

    ```jsx theme={null}
    "use client";
    import { useQuery } from "@tanstack/react-query";

    function Users() {
      const { data, error, isLoading } = useQuery({
        queryKey: ["users"],
        queryFn: () => fetch("/api/users").then(r => r.json()),
      });

      if (isLoading) return <p>Loading...</p>;
      if (error) return <p>Error: {error.message}</p>;
      return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
    }
    ```
  </Accordion>

  <Accordion title="How can you persist state across pages or reloads?">
    You can persist state using:

    * LocalStorage / SessionStorage
    * URL query params
    * Redux Persist or Zustand middleware

    ## Example (Zustand persist):

    ```jsx theme={null}
    import { create } from "zustand";
    import { persist } from "zustand/middleware";

    export const useUserStore = create(
      persist(
        (set) => ({
          name: "",
          setName: (name) => set({ name }),
        }),
        { name: "user-storage" }
      )
    );
    ```

    ## Usage:

    ```jsx theme={null}
    "use client";
    import { useUserStore } from "./useUserStore";

    export default function Profile() {
      const { name, setName } = useUserStore();
      return (
        <>
          <input value={name} onChange={(e) => setName(e.target.value)} />
          <p>Hello, {name}</p>
        </>
      );
    }
    ```
  </Accordion>

  <Accordion title="How do you prefetch data in Next.js App Router?">
    You can use React's async Server Components to fetch before rendering (SSR-like behavior).

    ## Example:

    ```jsx theme={null}
    // app/users/page.tsx
    export default async function UsersPage() {
      const users = await fetch("https://api.example.com/users", {
        cache: "no-store", // SSR-like
      }).then(r => r.json());

      return (
        <div>
          {users.map(u => <p key={u.id}>{u.name}</p>)}
        </div>
      );
    }
    ```

    ## Options:

    * `cache: "no-store"` → always fresh (SSR)
    * `next: { revalidate: 60 }` → ISR caching
  </Accordion>

  <Accordion title="What are Higher-Order Components (HOCs) and when would you use them?">
    HOCs are functions that take a component and return a new component with added functionality. They're used to share logic across multiple components (like authentication, logging, or analytics).

    ## Example:

    ```jsx theme={null}
    // withAuth.js
    const withAuth = (WrappedComponent) => {
      return function AuthenticatedComponent(props) {
        const isAuthenticated = Boolean(localStorage.getItem("token"));
        if (!isAuthenticated) {
          return <p>Please login first</p>;
        }
        return <WrappedComponent {...props} />;
      };
    };

    // Usage
    const Dashboard = () => <h2>Welcome to Dashboard</h2>;
    export default withAuth(Dashboard);
    ```
  </Accordion>

  <Accordion title="What is the Render Props pattern?">
    Render Props is a technique where a component accepts a function as a prop and uses it to determine what to render. It helps in sharing logic between components without using HOCs.

    ## Example:

    ```jsx theme={null}
    // MouseTracker.js
    function MouseTracker({ render }) {
      const [pos, setPos] = React.useState({ x: 0, y: 0 });
      return (
        <div onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>
          {render(pos)}
        </div>
      );
    }

    // Usage
    <MouseTracker render={({ x, y }) => <p>Mouse at {x}, {y}</p>} />
    ```
  </Accordion>

  <Accordion title="What is Compound Components pattern?">
    Compound components allow multiple components to work together, sharing implicit state via React Context.

    ## Example:

    ```jsx theme={null}
    const TabsContext = React.createContext();

    function Tabs({ children }) {
      const [active, setActive] = React.useState(0);
      return (
        <TabsContext.Provider value={{ active, setActive }}>
          <div>{children}</div>
        </TabsContext.Provider>
      );
    }

    function TabList({ children }) {
      return <div>{children}</div>;
    }

    function Tab({ index, children }) {
      const { active, setActive } = React.useContext(TabsContext);
      return (
        <button
          onClick={() => setActive(index)}
          style={{ fontWeight: active === index ? "bold" : "normal" }}
        >
          {children}
        </button>
      );
    }

    function TabPanels({ children }) {
      const { active } = React.useContext(TabsContext);
      return <div>{children[active]}</div>;
    }

    // Usage
    <Tabs>
      <TabList>
        <Tab index={0}>Profile</Tab>
        <Tab index={1}>Settings</Tab>
      </TabList>
      <TabPanels>
        <div>Profile content</div>
        <div>Settings content</div>
      </TabPanels>
    </Tabs>
    ```
  </Accordion>

  <Accordion title="What is the Provider Pattern?">
    The Provider Pattern exposes shared data and behavior to components via React Context. It's heavily used for themes, authentication, and state management.

    ## Example:

    ```jsx theme={null}
    const ThemeContext = React.createContext();

    export function ThemeProvider({ children }) {
      const [theme, setTheme] = React.useState("light");
      const toggle = () => setTheme(t => (t === "light" ? "dark" : "light"));

      return (
        <ThemeContext.Provider value={{ theme, toggle }}>
          {children}
        </ThemeContext.Provider>
      );
    }

    // Usage
    function ThemeToggleButton() {
      const { theme, toggle } = React.useContext(ThemeContext);
      return <button onClick={toggle}>Theme: {theme}</button>;
    }
    ```
  </Accordion>

  <Accordion title="What is code-splitting and how do you implement it in React?">
    Code-splitting helps load only the code needed for the current page, improving performance. React provides `React.lazy()` and `Suspense` for this.

    ## Example:

    ```jsx theme={null}
    const Dashboard = React.lazy(() => import("./Dashboard"));

    function App() {
      return (
        <React.Suspense fallback={<p>Loading...</p>}>
          <Dashboard />
        </React.Suspense>
      );
    }
    ```

    <Info>
      In Next.js, code-splitting is automatic per page.
    </Info>
  </Accordion>

  <Accordion title="How do you structure large React or Next.js projects?">
    A common scalable structure:

    ```
    src/
     ├── app/
     │    ├── (routes)
     │    ├── layout.tsx
     │    └── page.tsx
     ├── components/
     │    ├── ui/
     │    ├── forms/
     │    ├── layout/
     ├── hooks/
     ├── context/
     ├── lib/
     ├── services/
     ├── store/
     ├── styles/
     └── utils/
    ```

    * **Feature-based organization** helps scale
    * **Shared state or UI logic** goes to `/context` or `/hooks`
    * **Pages are lazy-loaded** in Next.js automatically
  </Accordion>

  <Accordion title="What are error boundaries and how do they work?">
    Error boundaries catch JavaScript errors in React components and show fallback UIs instead of breaking the app. They only work in class components.

    ## Example:

    ```jsx theme={null}
    class ErrorBoundary extends React.Component {
      state = { hasError: false };
      static getDerivedStateFromError() {
        return { hasError: true };
      }
      componentDidCatch(error, info) {
        console.error("Error logged:", error, info);
      }
      render() {
        if (this.state.hasError) return <h2>Something went wrong!</h2>;
        return this.props.children;
      }
    }

    // Usage
    <ErrorBoundary>
      <ComponentThatMayCrash />
    </ErrorBoundary>
    ```
  </Accordion>

  <Accordion title="Explain the concept of render optimization in React">
    To prevent unnecessary re-renders:

    * Use `React.memo()` for pure functional components
    * Use `useCallback` and `useMemo` to memoize functions and computed values
    * Avoid creating new objects/functions in render unnecessarily

    ## Example:

    ```jsx theme={null}
    const Button = React.memo(({ onClick }) => {
      console.log("Rendered Button");
      return <button onClick={onClick}>Click me</button>;
    });

    function App() {
      const handleClick = React.useCallback(() => console.log("Clicked!"), []);
      return <Button onClick={handleClick} />;
    }
    ```
  </Accordion>

  <Accordion title="What is the difference between a monolithic and modular frontend architecture?">
    | Aspect     | Monolithic                                           | Modular (Micro-frontend)                                           |
    | ---------- | ---------------------------------------------------- | ------------------------------------------------------------------ |
    | Structure  | All components tightly coupled and deployed together | App divided into independent modules (built & deployed separately) |
    | Team Size  | Better for small teams                               | Ideal for large teams, multiple domains                            |
    | Deployment | Single deployment                                    | Independent deployments                                            |
    | Tech Stack | Single technology                                    | Tech diversity (React + Vue + Angular)                             |

    ## When to use Modular:

    * Large teams, multiple domains
    * Independent deployments
    * Tech diversity requirements
  </Accordion>

  <Accordion title="How do you manage global state in large apps?">
    Options:

    * **Context API** for light global state
    * **Redux Toolkit / Zustand / Jotai** for complex or shared logic
    * **React Query** for server state

    ## Example with Zustand:

    ```jsx theme={null}
    import { create } from "zustand";

    const useStore = create((set) => ({
      count: 0,
      increase: () => set((state) => ({ count: state.count + 1 })),
    }));

    function Counter() {
      const { count, increase } = useStore();
      return <button onClick={increase}>Count: {count}</button>;
    }
    ```
  </Accordion>
</AccordionGroup>

<hr />

## 8. React and Next JS testing

<AccordionGroup>
  <Accordion title="Why is testing important in React apps?">
    Testing ensures that UI and logic behave as expected after changes. It helps catch regressions early and builds confidence in refactoring.

    ## Types of tests:

    * **Unit tests** → Test small pieces (functions, components)
    * **Integration tests** → Verify component interaction
    * **E2E tests** → Test entire user flows (via Playwright / Cypress)
  </Accordion>

  <Accordion title="What testing libraries are commonly used in React and Next.js?">
    * **Jest** → Testing framework (built-in with Next.js)
    * **React Testing Library (RTL)** → DOM interaction & behavior testing
    * **Playwright / Cypress** → End-to-end browser testing
  </Accordion>

  <Accordion title="How do you test a simple React component using Jest and RTL?">
    ## Example Component:

    ```jsx theme={null}
    // Counter.js
    export default function Counter() {
      const [count, setCount] = React.useState(0);
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount((c) => c + 1)}>Increment</button>
        </div>
      );
    }
    ```

    ## Test File:

    ```jsx theme={null}
    // Counter.test.js
    import { render, screen, fireEvent } from "@testing-library/react";
    import Counter from "./Counter";

    test("increments counter when button clicked", () => {
      render(<Counter />);
      fireEvent.click(screen.getByText("Increment"));
      expect(screen.getByText("Count: 1")).toBeInTheDocument();
    });
    ```

    <Check>
      Key Concept: RTL focuses on testing how users interact, not implementation details.
    </Check>
  </Accordion>

  <Accordion title="How do you mock API calls in tests?">
    You can use Jest's `jest.fn()` or libraries like MSW (Mock Service Worker).

    ## Example using Jest mock:

    ```jsx theme={null}
    // fetchUser.js
    export const fetchUser = async () => {
      const res = await fetch("/api/user");
      return res.json();
    };

    // fetchUser.test.js
    import { fetchUser } from "./fetchUser";

    global.fetch = jest.fn(() =>
      Promise.resolve({ json: () => Promise.resolve({ name: "Shehroze" }) })
    );

    test("fetches user correctly", async () => {
      const user = await fetchUser();
      expect(user.name).toBe("Shehroze");
    });
    ```
  </Accordion>

  <Accordion title="How do you test Next.js pages or server functions?">
    You can test server actions, API routes, or getServerSideProps using Jest's mocks.

    ## Example:

    ```jsx theme={null}
    // app/api/hello/route.js
    export async function GET() {
      return Response.json({ message: "Hello Next.js" });
    }

    // route.test.js
    import { GET } from "./route";

    test("returns hello message", async () => {
      const response = await GET();
      const data = await response.json();
      expect(data.message).toBe("Hello Next.js");
    });
    ```
  </Accordion>

  <Accordion title="How do you perform snapshot testing in React?">
    Snapshot tests ensure UI doesn't change unexpectedly.

    ## Example:

    ```jsx theme={null}
    import { render } from "@testing-library/react";
    import Button from "./Button";

    test("renders correctly", () => {
      const { asFragment } = render(<Button label="Click me" />);
      expect(asFragment()).toMatchSnapshot();
    });
    ```

    <Info>
      If the UI changes, Jest will show a diff.
    </Info>
  </Accordion>

  <Accordion title="How do you test components that use React Context?">
    Wrap your component inside the provider in the test.

    ## Example:

    ```jsx theme={null}
    // ThemeContext.js
    const ThemeContext = React.createContext();
    export const ThemeProvider = ({ children }) => (
      <ThemeContext.Provider value="dark">{children}</ThemeContext.Provider>
    );
    export default ThemeContext;

    // ThemedText.js
    import ThemeContext from "./ThemeContext";
    export default function ThemedText() {
      const theme = React.useContext(ThemeContext);
      return <p>Theme: {theme}</p>;
    }

    // ThemedText.test.js
    import { render, screen } from "@testing-library/react";
    import { ThemeProvider } from "./ThemeContext";
    import ThemedText from "./ThemedText";

    test("renders theme from context", () => {
      render(
        <ThemeProvider>
          <ThemedText />
        </ThemeProvider>
      );
      expect(screen.getByText("Theme: dark")).toBeInTheDocument();
    });
    ```
  </Accordion>

  <Accordion title="How do you debug React apps efficiently?">
    * Use **React Developer Tools** in browser
    * Add `console.log()` inside hooks or effects
    * Use **VSCode breakpoints**
    * Use **why-did-you-render** library to detect unnecessary re-renders
    * For Next.js, run `next dev --inspect` for Node debugging
  </Accordion>

  <Accordion title="How do you handle test coverage?">
    Jest has built-in coverage reporting:

    ```bash theme={null}
    npm run test -- --coverage
    ```

    It generates a report showing what percentage of lines, functions, and branches are tested.

    ## Key metrics to aim for:

    * **80%+** line coverage
    * **70%+** branch coverage
  </Accordion>

  <Accordion title="What are common issues you debug in Next.js?">
    | Problem               | Possible Cause                            | Solution                                      |
    | --------------------- | ----------------------------------------- | --------------------------------------------- |
    | Hydration Error       | Mismatch between SSR and client rendering | Avoid using browser-only APIs during SSR      |
    | API Route not working | Wrong file structure or method name       | Ensure correct `/app/api/.../route.js` naming |
    | 404 after deploy      | Static export paths missing               | Check dynamic routes and revalidate configs   |
    | Performance lag       | Over-fetching or large bundle             | Use lazy loading, memoization, code-splitting |
  </Accordion>

  <Accordion title="How do you test components using async effects?">
    ## Example Component:

    ```jsx theme={null}
    // UserProfile.js
    export default function UserProfile() {
      const [user, setUser] = React.useState(null);
      React.useEffect(() => {
        fetch("/api/user")
          .then((res) => res.json())
          .then(setUser);
      }, []);
      if (!user) return <p>Loading...</p>;
      return <p>Hello, {user.name}</p>;
    }
    ```

    ## Test File:

    ```jsx theme={null}
    // UserProfile.test.js
    import { render, screen, waitFor } from "@testing-library/react";
    import UserProfile from "./UserProfile";

    global.fetch = jest.fn(() =>
      Promise.resolve({ json: () => Promise.resolve({ name: "Shehroze" }) })
    );

    test("renders user after fetch", async () => {
      render(<UserProfile />);
      await waitFor(() => expect(screen.getByText("Hello, Shehroze")).toBeInTheDocument());
    });
    ```
  </Accordion>
</AccordionGroup>

## 9. Performance and Optimization React | Next JS

<AccordionGroup>
  <Accordion title="How do you prevent unnecessary re-renders in React?">
    To prevent unnecessary re-renders in React:

    * Wrap pure components with `React.memo`
    * Use `useCallback` to memoize event handlers
    * Use `useMemo` for computed values
    * Split large components
    * Keep state as local as possible

    ## Example:

    ```jsx theme={null}
    const Child = React.memo(({ value }) => {
      console.log("Child rendered");
      return <p>{value}</p>;
    });

    function App() {
      const [count, setCount] = React.useState(0);
      const memoValue = React.useMemo(() => count * 2, [count]);
      return (
        <>
          <Child value={memoValue} />
          <button onClick={() => setCount((c) => c + 1)}>Increment</button>
        </>
      );
    }
    ```
  </Accordion>

  <Accordion title="How do you optimize images and assets in Next.js?">
    Use the built-in `next/image` component for automatic:

    * Lazy loading
    * Responsive sizes
    * Format optimization (WebP/AVIF)

    ## Example:

    ```jsx theme={null}
    import Image from "next/image";

    export default function Hero() {
      return (
        <Image
          src="/hero.jpg"
          alt="Hero Image"
          width={1200}
          height={600}
          priority
        />
      );
    }
    ```

    ## Tips:

    * Use `priority` for above-the-fold images
    * Use `blurDataURL` for placeholder effect
  </Accordion>

  <Accordion title="How do you handle large bundle sizes?">
    * Use dynamic imports:

    ```jsx theme={null}
    const Chart = dynamic(() => import("../components/Chart"), { ssr: false });
    ```

    * Analyze with:

    ```bash theme={null}
    npm run build && npx next analyze
    ```

    * Move heavy logic to server components (Next.js App Router)
  </Accordion>

  <Accordion title="How does React Suspense help performance?">
    Suspense lets you pause rendering while data is loading, improving perceived performance.

    ## Example:

    ```jsx theme={null}
    const User = React.lazy(() => import("./User"));

    function App() {
      return (
        <React.Suspense fallback={<p>Loading user...</p>}>
          <User />
        </React.Suspense>
      );
    }
    ```
  </Accordion>

  <Accordion title="What are server and client components in Next.js 13+?">
    * **Server Components**: Run on the server; ideal for data fetching and heavy logic
    * **Client Components**: Run in the browser; used for interactivity

    ## Example:

    ```jsx theme={null}
    // server component (default)
    export default async function Page() {
      const data = await fetch("https://api.example.com/posts").then(r => r.json());
      return <List posts={data} />;
    }

    // client component
    "use client";
    export function List({ posts }) {
      return posts.map(p => <p key={p.id}>{p.title}</p>);
    }
    ```
  </Accordion>

  <Accordion title="How do you cache API responses in Next.js?">
    * Use `revalidate` for ISR (Incremental Static Regeneration)
    * Use fetch caching options (`force-cache`, `no-store`, `revalidate`)

    ## Example:

    ```jsx theme={null}
    export default async function Page() {
      const res = await fetch("https://api.example.com/data", { 
        next: { revalidate: 60 } 
      });
      const data = await res.json();
      return <div>{data.title}</div>;
    }
    ```
  </Accordion>

  <Accordion title="What are some performance debugging tools?">
    * **React Profiler** → Measures render time
    * **Lighthouse** → Measures Core Web Vitals
    * **Next.js build analyzer** → Bundle size breakdown
    * **Chrome DevTools Performance tab** → JS execution time
  </Accordion>

  <Accordion title="What are React rendering phases and how to profile them?">
    React rendering has:

    1. **Render phase** → Reconciliation (diffing virtual DOM)
    2. **Commit phase** → Apply changes to real DOM

    <Info>
      Use React DevTools Profiler to visualize and measure these phases.
    </Info>
  </Accordion>

  <Accordion title="How do you handle performance in lists (1000+ items)?">
    * Use windowing (e.g. react-window or react-virtualized)
    * Use key properly
    * Paginate data

    ## Example:

    ```jsx theme={null}
    import { FixedSizeList as List } from "react-window";

    const Row = ({ index, style }) => <div style={style}>Row {index}</div>;

    <List height={400} width={300} itemCount={1000} itemSize={35}>
      {Row}
    </List>;
    ```
  </Accordion>

  <Accordion title="What are best practices for Next.js SEO performance?">
    * Use `generateMetadata()` in App Router
    * Lazy load below-the-fold components
    * Preload fonts via `next/font`
    * Optimize routes with static rendering when possible
    * Use semantic HTML and proper heading structure
    * Implement structured data with JSON-LD
    * Ensure fast loading times with image optimization
  </Accordion>
</AccordionGroup>

## 10. Security and Best Practices in React | Next JS

<AccordionGroup>
  <Accordion title="How do you prevent XSS (Cross-Site Scripting) in React?">
    React escapes all strings by default, preventing XSS unless you use `dangerouslySetInnerHTML`.

    ## Safe Practice:

    Never insert user input into HTML directly.

    ```jsx theme={null}
    <p>{userInput}</p> // ✅ Safe
    <div dangerouslySetInnerHTML={{ __html: userInput }} /> // ❌ Dangerous
    ```

    If you must, sanitize it using DOMPurify:

    ```jsx theme={null}
    import DOMPurify from "dompurify";
    <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />;
    ```
  </Accordion>

  <Accordion title="How do you secure API routes in Next.js?">
    * Use authentication middleware
    * Validate incoming data with Zod or Yup
    * Restrict methods (GET, POST, etc.)
    * Avoid exposing sensitive env vars to the client

    ## Example:

    ```jsx theme={null}
    // app/api/user/route.js
    import { auth } from "@/lib/auth";
    import { z } from "zod";

    const schema = z.object({ name: z.string() });

    export async function POST(req) {
      const user = await auth(req);
      if (!user) return new Response("Unauthorized", { status: 401 });

      const body = await req.json();
      schema.parse(body);
      // safe to use body.name
    }
    ```
  </Accordion>

  <Accordion title="How do you store secrets securely in Next.js?">
    * Use `.env.local` for local secrets
    * Access via `process.env.SECRET_KEY` on server
    * Never expose private keys using `NEXT_PUBLIC_` prefix unless intentional

    <Warning>
      Environment variables without `NEXT_PUBLIC_` prefix are only available on the server side.
    </Warning>
  </Accordion>

  <Accordion title="How do you prevent CSRF attacks?">
    * Use tokens or double-submit cookies
    * For sensitive actions, validate Origin and Referer headers
    * Use libraries like NextAuth.js (handles CSRF internally)
    * Implement SameSite cookies

    ## Example cookie settings:

    ```jsx theme={null}
    cookies.set("token", jwt, { 
      httpOnly: true, 
      secure: true, 
      sameSite: "strict" 
    });
    ```
  </Accordion>

  <Accordion title="How do you handle authentication securely?">
    * Use HTTP-only cookies for tokens
    * Avoid storing JWT in localStorage (can be stolen via XSS)
    * Implement proper session management
    * Use secure and sameSite flags for cookies

    ## Secure cookie configuration:

    ```jsx theme={null}
    cookies.set("token", jwt, { 
      httpOnly: true, 
      secure: true, 
      sameSite: "strict" 
    });
    ```

    <Info>
      HTTP-only cookies prevent JavaScript access, reducing XSS attack impact.
    </Info>
  </Accordion>

  <Accordion title="What are CSP (Content Security Policies)?">
    A CSP header restricts sources for scripts, styles, images, etc., reducing XSS risk.

    ## Example:

    ```jsx theme={null}
    // next.config.js
    async headers() {
      return [
        {
          source: "/(.*)",
          headers: [
            {
              key: "Content-Security-Policy",
              value: "default-src 'self'; img-src https: data:; script-src 'self';",
            },
          ],
        },
      ];
    }
    ```

    <Note>
      CSP helps prevent XSS attacks by whitelisting trusted sources for content loading.
    </Note>
  </Accordion>

  <Accordion title="How do you handle rate limiting for APIs?">
    Use middleware like Upstash, Redis, or rate-limiter-flexible.

    ## Example (middleware):

    ```jsx theme={null}
    import { Ratelimit } from "@upstash/ratelimit";
    import { Redis } from "@upstash/redis";

    const ratelimit = new Ratelimit({
      redis: Redis.fromEnv(),
      limiter: Ratelimit.fixedWindow(10, "60 s"),
    });

    export async function middleware(req) {
      const ip = req.ip ?? "127.0.0.1";
      const { success } = await ratelimit.limit(ip);
      if (!success) return new Response("Too many requests", { status: 429 });
      return NextResponse.next();
    }
    ```
  </Accordion>

  <Accordion title="How do you prevent sensitive data exposure in logs?">
    Never log JWTs, passwords, or full API responses. Mask sensitive data before logging.

    ## Example:

    ```jsx theme={null}
    // ❌ Don't do this
    console.log({ email, password: userPassword });

    // ✅ Do this instead
    console.log({ email, password: "***" });

    // For debugging, use redaction
    const safeLog = (data) => {
      const { password, token, ...safeData } = data;
      console.log({ ...safeData, sensitive: "REDACTED" });
    };
    ```

    <Warning>
      Always redact sensitive information before logging to prevent data leaks.
    </Warning>
  </Accordion>

  <Accordion title="How to handle CORS safely?">
    * Always whitelist origins
    * Avoid using `*` in production
    * Use middleware to configure headers

    ## Example:

    ```jsx theme={null}
    export const config = { api: { bodyParser: false } };
    export default function handler(req, res) {
      res.setHeader("Access-Control-Allow-Origin", "https://trusted.com");
      res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT");
      res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
    }
    ```

    <Info>
      Never use `Access-Control-Allow-Origin: *` in production for sensitive endpoints.
    </Info>
  </Accordion>

  <Accordion title="How to secure Next.js deployment?">
    ## Security Checklist:

    * ✅ Use HTTPS
    * ✅ Set `NODE_ENV=production`
    * ✅ Use environment variables, not hardcoded secrets
    * ✅ Keep dependencies updated (`npm audit`)
    * ✅ Use a WAF (Web Application Firewall) if available
    * ✅ Implement proper CORS policies
    * ✅ Use security headers (CSP, HSTS, X-Frame-Options)
    * ✅ Regular security scanning and penetration testing
    * ✅ Monitor for suspicious activities
    * ✅ Implement proper error handling (don't leak stack traces)

    <Check>
      Regular security audits and dependency updates are crucial for maintaining application security.
    </Check>
  </Accordion>

  <Accordion title="How do you protect sensitive environment variables in Next.js?">
    Environment variables starting with `NEXT_PUBLIC_` are exposed to the client. Sensitive keys (like API secrets or DB credentials) must not use `NEXT_PUBLIC_` and should only be accessed on the server (API routes, getServerSideProps, or server components).

    ## Example:

    ```bash theme={null}
    # .env.local
    NEXT_PUBLIC_API_URL=https://api.example.com
    SECRET_API_KEY=my_super_secret_key
    ```

    ```jsx theme={null}
    // app/api/data/route.js
    export async function GET() {
      const res = await fetch("https://secureapi.com", {
        headers: { Authorization: `Bearer ${process.env.SECRET_API_KEY}` },
      });
      const data = await res.json();
      return Response.json(data);
    }
    ```

    <Check>
      Secret key never goes to the browser when not using NEXT\_PUBLIC\_ prefix.
    </Check>
  </Accordion>

  <Accordion title="What are some common security vulnerabilities in React apps and how do you prevent them?">
    ## 1️⃣ XSS (Cross-Site Scripting):

    Occurs when malicious scripts are injected into the DOM.

    **✅ Fix:**

    * Avoid `dangerouslySetInnerHTML`
    * Sanitize input using libraries like DOMPurify

    ```jsx theme={null}
    import DOMPurify from "dompurify";

    function SafeHtml({ html }) {
      return <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html) }} />;
    }
    ```

    ## 2️⃣ CSRF (Cross-Site Request Forgery):

    Attackers trick users into making unwanted requests.

    **✅ Fix:**

    * Use anti-CSRF tokens (NextAuth and other libs handle this)
    * Validate origin headers in API routes

    ## 3️⃣ Data Leakage via Source Code:

    Leaking private tokens in frontend code.

    **✅ Fix:**

    * Never expose secrets in `NEXT_PUBLIC_` vars
    * Validate .env usage during CI/CD

    ## 4️⃣ Insecure Direct Object Reference (IDOR):

    Users access others' data by manipulating IDs.

    **✅ Fix:**

    * Always verify authorization on the server
    * Never trust frontend route params
  </Accordion>

  <Accordion title="How do you handle authentication securely in Next.js?">
    ## Approach 1: Using NextAuth.js

    ```jsx theme={null}
    // app/api/auth/[...nextauth]/route.js
    import NextAuth from "next-auth";
    import CredentialsProvider from "next-auth/providers/credentials";

    const handler = NextAuth({
      providers: [
        CredentialsProvider({
          async authorize(credentials) {
            const res = await fetch("https://api.example.com/login", {
              method: "POST",
              body: JSON.stringify(credentials),
            });
            const user = await res.json();
            if (user?.token) return user;
            return null;
          },
        }),
      ],
      session: { strategy: "jwt" },
    });

    export { handler as GET, handler as POST };
    ```

    <Check>
      Uses server-side token validation. Sessions stored as HTTP-only cookies (protects from XSS).
    </Check>
  </Accordion>

  <Accordion title="What are HTTP-only cookies and why are they more secure?">
    * **HttpOnly flag** prevents JavaScript from reading cookies
    * Reduces XSS impact since scripts can't access sensitive tokens

    ## Example:

    ```jsx theme={null}
    // Setting cookie securely
    cookies().set("token", jwt, { 
      httpOnly: true, 
      secure: true, 
      sameSite: "Strict" 
    });
    ```

    <Info>
      Prevents token theft from browser scripts by making cookies inaccessible to JavaScript.
    </Info>
  </Accordion>

  <Accordion title="How do you handle CORS securely?">
    CORS controls which domains can make API requests.

    ## Example:

    ```jsx theme={null}
    // app/api/route.js
    export async function GET(req) {
      return new Response("ok", {
        headers: {
          "Access-Control-Allow-Origin": "https://yourdomain.com",
          "Access-Control-Allow-Credentials": "true",
        },
      });
    }
    ```

    <Warning>
      Never use "\*" for production as it allows any domain to access your API.
    </Warning>
  </Accordion>

  <Accordion title="How do you prevent open redirects in Next.js?">
    Attackers could redirect users to malicious sites.

    **✅ Fix:**
    Validate redirect URLs before allowing them:

    ```jsx theme={null}
    export async function POST(req) {
      const { redirectUrl } = await req.json();
      const safeDomains = ["example.com", "app.example.com"];
      const url = new URL(redirectUrl);

      if (!safeDomains.includes(url.hostname))
        return new Response("Invalid redirect", { status: 400 });

      return Response.redirect(redirectUrl);
    }
    ```
  </Accordion>

  <Accordion title="How to secure API routes in Next.js?">
    ## Example:

    ```jsx theme={null}
    import { cookies } from "next/headers";

    export async function GET() {
      const token = cookies().get("token");
      if (!token) return Response.json({ error: "Unauthorized" }, { status: 401 });
      
      // verify JWT, then fetch data
      const user = await verifyToken(token.value);
      return Response.json({ data: user });
    }
    ```

    <Check>
      Authentication handled on the server, not the client.
    </Check>
  </Accordion>

  <Accordion title="What is CSP (Content Security Policy) and how does it protect your app?">
    CSP prevents malicious scripts or resources from loading.

    ## Example:

    ```jsx theme={null}
    // next.config.js
    const securityHeaders = [
      {
        key: "Content-Security-Policy",
        value: "default-src 'self'; img-src *; script-src 'self'; style-src 'self';",
      },
    ];

    module.exports = {
      async headers() {
        return [{ source: "/(.*)", headers: securityHeaders }];
      },
    };
    ```

    <Info>
      Helps prevent XSS and data injection attacks by restricting content sources.
    </Info>
  </Accordion>

  <Accordion title="How do you secure Next.js API endpoints with JWT?">
    ## Example:

    ```jsx theme={null}
    import jwt from "jsonwebtoken";
    import { cookies } from "next/headers";

    export async function GET() {
      const token = cookies().get("token")?.value;
      if (!token) return Response.json({ message: "No token" }, { status: 401 });

      try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        return Response.json({ user: decoded });
      } catch {
        return Response.json({ message: "Invalid token" }, { status: 403 });
      }
    }
    ```

    <Check>
      Validates access at runtime using JWT verification.
    </Check>
  </Accordion>

  <Accordion title="How do you secure Next.js Server Actions or Route Handlers?">
    ## Example:

    ```jsx theme={null}
    "use server";
    import { cookies } from "next/headers";

    export async function deleteUserAccount() {
      const token = cookies().get("token");
      if (!token) throw new Error("Unauthorized");

      // call backend securely
      await deleteAccountFromDatabase();
    }
    ```

    <Check>
      Server actions run on the server only, so secrets remain safe.
    </Check>
  </Accordion>

  <Accordion title="What are some best practices for secure React + Next.js apps?">
    | Category          | Best Practice                                       |
    | ----------------- | --------------------------------------------------- |
    | 🔐 Authentication | Use JWT or NextAuth with HttpOnly cookies           |
    | 🔑 Secrets        | Store in .env.local, never in client                |
    | 🧱 XSS            | Sanitize HTML, avoid dangerouslySetInnerHTML        |
    | 🔄 CSRF           | Use anti-CSRF tokens or same-site cookies           |
    | 🧭 Routing        | Validate redirect URLs                              |
    | 🧰 Packages       | Audit dependencies with `npm audit`                 |
    | ⚙️ Headers        | Set CSP, X-Frame-Options, Strict-Transport-Security |
    | 📦 API            | Rate limit requests and validate input              |
    | 📡 HTTPS          | Always use SSL in production                        |

    <Info>
      Regular security audits and dependency updates are essential for maintaining application security.
    </Info>
  </Accordion>
</AccordionGroup>

## 11. Node.js Advanced Topics

<AccordionGroup>
  <Accordion title="What is Node.js?">
    Node.js is a **JavaScript runtime** built on Chrome's V8 engine that allows JavaScript to run outside the browser -- primarily on servers. But "JavaScript on the server" undersells it. The real innovation is Node's **event-driven, non-blocking I/O model** which makes it exceptionally good at handling many concurrent connections with minimal resources.

    **Why Node.js is architecturally different from traditional servers:**

    * **Traditional servers (Apache, Tomcat):** One thread per connection. 10,000 concurrent users = 10,000 threads. Each thread consumes \~2MB of RAM. That is 20GB just for threads
    * **Node.js:** Single thread + event loop + non-blocking I/O. 10,000 concurrent users share one thread. The event loop delegates I/O operations to the OS kernel or libuv's thread pool, so the main thread is never blocked waiting for disk/network

    **Where Node.js excels:**

    * **I/O-bound applications** -- APIs, real-time apps (chat, gaming), microservices, streaming
    * Not ideal for **CPU-bound tasks** (image processing, video encoding, heavy computation) because they block the single thread. For these, use Worker Threads or offload to a different service

    **The V8 engine connection:**
    V8 compiles JavaScript to machine code using JIT (Just-In-Time) compilation, making Node.js surprisingly fast for a dynamic language -- within 2-5x of C++ for many workloads.

    **What interviewers are really testing:** Whether you understand the event-driven architecture that makes Node unique, not just that it "runs JS on the server."

    **Red flag answer:** "Node.js is a server-side JavaScript framework." It is a runtime (not a framework), and the important part is *how* it handles concurrency.

    **Follow-up:**

    1. Why is Node.js not recommended for CPU-intensive tasks? What happens to other requests when a CPU-heavy operation is running?
    2. How does Node.js handle 10,000 concurrent connections with a single thread?
    3. What is the difference between Node.js and Deno? Why did Ryan Dahl create Deno?
  </Accordion>

  <Accordion title="Explain the Node.js Event Loop. How does it handle asynchronous operations?">
    Node.js is single-threaded, but it handles concurrency using the event loop, which is part of the libuv library. The event loop allows Node.js to perform non-blocking I/O operations, even though JavaScript runs on a single thread.

    ## Event Loop Phases (TCCPPI)

    1. **Timers** – Executes callbacks from `setTimeout()` and `setInterval()`
    2. **Pending Callbacks** – Executes I/O callbacks deferred from the previous cycle
    3. **Idle / Prepare** – Internal use
    4. **Poll** – Retrieves new I/O events; executes their callbacks
    5. **Check** – Executes callbacks from `setImmediate()`
    6. **Close Callbacks** – Executes callbacks like `socket.on('close')`

    ## Example

    ```javascript theme={null}
    setTimeout(() => console.log("Timeout"), 0);
    setImmediate(() => console.log("Immediate"));
    process.nextTick(() => console.log("NextTick"));
    console.log("Sync");
    ```

    **Output:**

    ```
    Sync
    NextTick
    Timeout
    Immediate
    ```

    ## Why this order?

    * `process.nextTick()` runs before the event loop continues
    * Timers (`setTimeout`) are queued for the Timers phase
    * `setImmediate()` runs during the Check phase

    ## When to use:

    * Use `process.nextTick()` for micro-tasks after the current operation
    * Use `setImmediate()` for tasks after I/O events are processed

    **What interviewers are really testing:** Whether you can trace the execution order of mixed sync/async code and explain *why* each runs when it does. This is the single most-asked Node.js interview question.

    **Red flag answer:** "The event loop handles async code." Too vague. A strong candidate names the phases, explains microtask vs macrotask queues, and can predict output order for mixed code.

    **Follow-up:**

    1. Where do Promises fit in the event loop? Are they part of the microtask queue or the macrotask queue?
    2. What happens if you call `process.nextTick()` recursively? How does it differ from recursive `setImmediate()`?
    3. Your API has an endpoint that takes 2 seconds to respond. 100 other requests are waiting. Is the event loop blocked? How can you tell?
  </Accordion>

  <Accordion title="What is the difference between process.nextTick() and setImmediate()?">
    Both schedule asynchronous callbacks, but they run at different times in the event loop.

    * **process.nextTick()** executes before the event loop continues — a micro-task
    * **setImmediate()** executes after the current poll phase — a macro-task

    ## Example:

    ```javascript theme={null}
    console.log('Start');
    process.nextTick(() => console.log('Next Tick'));
    setImmediate(() => console.log('Immediate'));
    console.log('End');
    ```

    **Output:**

    ```
    Start
    End
    Next Tick
    Immediate
    ```

    ## When to use:

    * Use `process.nextTick()` for quick callbacks that must run before I/O
    * Use `setImmediate()` when you want to yield to I/O first to prevent blocking
  </Accordion>

  <Accordion title="Explain how Node.js handles non-blocking I/O">
    Node.js uses libuv, a C library providing an event-driven, non-blocking I/O model. I/O operations (file read, network calls, etc.) are delegated to the OS kernel or libuv's thread pool, so Node's main thread stays free to handle other tasks.

    ## Example:

    ```javascript theme={null}
    const fs = require('fs');

    console.log('Start');
    fs.readFile('file.txt', 'utf8', (err, data) => {
      if (err) throw err;
      console.log('File read complete');
    });
    console.log('End');
    ```

    **Output:**

    ```
    Start
    End
    File read complete
    ```

    ## Why:

    The file read happens asynchronously; Node doesn't block waiting for it.

    ## Where/When:

    Used in high-throughput systems — e.g., API gateways, chat apps — where many concurrent requests are served without thread blocking.
  </Accordion>

  <Accordion title="What are Streams in Node.js?">
    Streams are continuous data flows — they let you process data chunk by chunk instead of loading it all into memory. They're instances of the EventEmitter class.

    ## Types of Streams:

    1. **Readable** – e.g. `fs.createReadStream()`
    2. **Writable** – e.g. `fs.createWriteStream()`
    3. **Duplex** – both readable and writable (e.g. TCP socket)
    4. **Transform** – modifies data while reading/writing (e.g. zlib compression)

    ## Example:

    ```javascript theme={null}
    const fs = require('fs');
    const read = fs.createReadStream('input.txt');
    const write = fs.createWriteStream('output.txt');

    read.pipe(write);
    ```

    ## Why:

    * Efficient for large files or live data (video, logs)
    * Uses constant memory regardless of file size -- a 10GB file uses the same \~64KB buffer whether you stream it or not

    ## Where:

    * File uploads/downloads (S3 streaming)
    * Real-time data transfer (video/audio streaming)
    * Log streaming and processing pipelines
    * HTTP response streaming (server-sent events)

    **Real-world example -- streaming a CSV export:**

    ```javascript theme={null}
    app.get('/export', (req, res) => {
      res.setHeader('Content-Type', 'text/csv');
      res.setHeader('Content-Disposition', 'attachment; filename="users.csv"');

      const cursor = User.find().cursor(); // MongoDB cursor is a Readable stream
      cursor.pipe(new CSVTransform()).pipe(res);
      // Memory usage stays constant even for 1M records
    });
    ```

    **The backpressure concept:** If the writable stream (e.g., network socket) is slower than the readable stream (e.g., file disk), Node.js automatically pauses the readable stream to prevent memory overflow. This is called backpressure and is handled by `.pipe()` automatically. When you use manual `write()` calls, you must handle backpressure yourself by checking the return value and listening for the `drain` event.

    **What interviewers are really testing:** Whether you understand memory-efficient data processing and can explain backpressure. This separates Node.js beginners from intermediate+ developers.

    **Red flag answer:** "Streams read files in chunks." This misses backpressure, piping, and the four stream types.

    **Follow-up:**

    1. What is backpressure in streams, and what happens if you ignore it?
    2. How would you implement a Transform stream that gzips data on the fly?
    3. When would you use `pipeline()` from the `stream` module instead of `.pipe()`?
  </Accordion>

  <Accordion title="What is the difference between spawn, fork, and exec in Node.js?">
    | Method | Description                                               | Use Case                             |
    | ------ | --------------------------------------------------------- | ------------------------------------ |
    | spawn  | Launches a new process                                    | For long-running or streaming output |
    | exec   | Launches a process and buffers entire output              | For small output commands            |
    | fork   | Special case of spawn that runs a Node.js script with IPC | For creating worker processes        |

    ## Example:

    ```javascript theme={null}
    const { spawn, exec, fork } = require('child_process');

    // spawn example
    const ls = spawn('ls', ['-lh', '/usr']);
    ls.stdout.on('data', data => console.log(`Spawn output: ${data}`));

    // exec example
    exec('ls -lh /usr', (err, stdout) => console.log(`Exec output: ${stdout}`));

    // fork example
    const child = fork('./worker.js');
    child.on('message', msg => console.log('Message from child:', msg));
    ```

    ## Why/When/Where:

    * Use **spawn** for streaming output (e.g., logs)
    * Use **exec** when you need full command output as a string
    * Use **fork** for scaling CPU-bound tasks or worker threads
  </Accordion>

  <Accordion title="What are Worker Threads and how do they differ from the Event Loop?">
    Worker Threads allow multi-threading in Node.js for CPU-intensive tasks, unlike the single-threaded event loop.

    ## Example:

    ```javascript theme={null}
    const { Worker, isMainThread, parentPort } = require('worker_threads');

    if (isMainThread) {
      const worker = new Worker(__filename);
      worker.on('message', msg => console.log('Received:', msg));
    } else {
      parentPort.postMessage('Hello from Worker');
    }
    ```

    ## Why:

    To offload heavy computations (e.g. image processing, encryption) so they don't block the main event loop.

    ## Where:

    In apps with mixed I/O and CPU workloads, like video encoding servers.
  </Accordion>

  <Accordion title="How do you handle uncaught exceptions and unhandled promise rejections?">
    You should always handle unexpected errors globally, but never rely solely on them — they indicate bugs that should be fixed.

    ## Example:

    ```javascript theme={null}
    process.on('uncaughtException', (err) => {
      console.error('Uncaught Exception:', err);
      process.exit(1); // Restart service safely
    });

    process.on('unhandledRejection', (reason) => {
      console.error('Unhandled Promise Rejection:', reason);
    });
    ```

    ## Why:

    Prevents app from crashing unexpectedly and allows logging/restarting.

    ## When/Where:

    Use this for graceful shutdown and to catch programming mistakes in production.
  </Accordion>

  <Accordion title="Explain Cluster Mode in Node.js and how it helps in scaling">
    Cluster mode allows you to spawn multiple Node.js processes (workers) to utilize multi-core CPUs. Each worker runs a separate instance of your app and shares the same server port via IPC managed by the cluster module.

    ## Example:

    ```javascript theme={null}
    const cluster = require('cluster');
    const http = require('http');
    const numCPUs = require('os').cpus().length;

    if (cluster.isPrimary) {
      for (let i = 0; i < numCPUs; i++) cluster.fork();
      cluster.on('exit', (worker) => cluster.fork());
    } else {
      http.createServer((req, res) => {
        res.end(`Handled by worker ${process.pid}`);
      }).listen(3000);
    }
    ```

    ## Why:

    * Single Node.js process uses only one CPU core
    * Cluster mode scales horizontally across all cores

    ## Where:

    Used in production APIs — e.g., Express servers, GraphQL APIs — to handle more traffic efficiently.
  </Accordion>

  <Accordion title="How does Node.js handle memory management?">
    Node.js uses V8's garbage collector, which manages heap memory automatically, but developers must avoid leaks.

    ## Common causes of leaks:

    * Global variables
    * Unclosed timers or listeners
    * Caching large data objects indefinitely

    ## Example Leak:

    ```javascript theme={null}
    const cache = {};
    setInterval(() => {
      cache[Math.random()] = new Array(1000000).join('x');
    }, 1000);
    ```

    **Fix:** Use WeakMap, clear intervals, or implement LRU caches.

    ## When/Where:

    Monitor memory with tools like:

    * `--inspect` + Chrome DevTools
    * clinic.js, heapdump, `node --trace-gc`
  </Accordion>

  <Accordion title="What are Buffers in Node.js?">
    Buffers are binary data containers — used to handle raw data (files, streams, sockets) that can't be represented as strings.

    ## Example:

    ```javascript theme={null}
    const buf = Buffer.from('Hello');
    console.log(buf); // <Buffer 48 65 6c 6c 6f>
    console.log(buf.toString()); // 'Hello'
    ```

    ## Why:

    Buffers allow manipulation of binary data efficiently (e.g., file systems, TCP streams).

    ## Where:

    Used in file operations, network protocols, and binary serialization.
  </Accordion>

  <Accordion title="What are Modules in Node.js and how are they resolved?">
    Node.js uses CommonJS (require) and ES Modules (import) systems.

    ## Example:

    ```javascript theme={null}
    // math.js
    module.exports.add = (a, b) => a + b;

    // app.js
    const { add } = require('./math');
    console.log(add(2, 3));
    ```

    ## Module Resolution Order:

    1. Core modules (fs, path)
    2. Local files (./, ../)
    3. node\_modules directory

    ## Why:

    Encapsulation of code — prevents global scope pollution.

    ## Where:

    Used in all Node.js apps; ES Modules preferred for modern codebases.
  </Accordion>

  <Accordion title="How do you structure a large-scale Node.js application?">
    Large Node.js applications need modular, layered architecture to keep code organized and maintainable.

    ## Common Structure:

    ```
    src/
     ┣ config/          # Environment variables, constants
     ┣ modules/
     ┃ ┣ user/
     ┃ ┃ ┣ user.controller.js
     ┃ ┃ ┣ user.service.js
     ┃ ┃ ┣ user.model.js
     ┃ ┃ ┣ user.routes.js
     ┣ middlewares/
     ┣ utils/
     ┣ app.js
     ┣ server.js
    ```

    ## Layers Explained:

    * **Controller**: Handles request/response (HTTP logic)
    * **Service**: Business logic
    * **Model**: Database schema and queries
    * **Middleware**: Reusable pre-processing (auth, validation)
    * **Routes**: Maps endpoints to controllers

    ## Why:

    * Improves separation of concerns
    * Enables unit testing per layer
    * Simplifies onboarding and scalability

    ## Where/When:

    Used in all enterprise-level Node.js APIs or microservices where team collaboration and modularization are essential.
  </Accordion>

  <Accordion title="What are some common design patterns used in Node.js?">
    Node.js heavily uses asynchronous and modular design patterns.

    ## Key Patterns:

    | Pattern    | Description                    | Example             | Use Case                      |
    | ---------- | ------------------------------ | ------------------- | ----------------------------- |
    | Singleton  | Single shared instance         | DB connection pool  | Database connections          |
    | Factory    | Creates objects dynamically    | Model creation      | Dynamic service instantiation |
    | Observer   | Event-driven                   | EventEmitter        | Real-time systems             |
    | Middleware | Chain of functions             | Express middlewares | API requests                  |
    | Repository | Abstract data layer            | Repository class    | Decoupled DB logic            |
    | Decorator  | Adds behavior without altering | Wrapping services   | Logging, caching              |

    ## Singleton Pattern Example:

    ```javascript theme={null}
    class Database {
      constructor() {
        if (Database.instance) return Database.instance;
        this.connection = this.connect();
        Database.instance = this;
      }
      connect() {
        console.log("DB connected");
        return {};
      }
    }
    const db1 = new Database();
    const db2 = new Database();
    console.log(db1 === db2); // true
    ```

    **Why:** Ensures only one DB connection exists across the app\
    **When:** Use for connection pools, config objects, caches

    ## Factory Pattern Example:

    ```javascript theme={null}
    class Payment {
      process() {}
    }

    class Paypal extends Payment {
      process() { console.log("PayPal Payment"); }
    }

    class Stripe extends Payment {
      process() { console.log("Stripe Payment"); }
    }

    class PaymentFactory {
      static create(type) {
        if (type === "paypal") return new Paypal();
        if (type === "stripe") return new Stripe();
      }
    }

    const payment = PaymentFactory.create("paypal");
    payment.process(); // PayPal Payment
    ```

    **Why:** Avoids tight coupling between code and object types\
    **When:** Use for service selection (e.g., multiple gateways, APIs)
  </Accordion>

  <Accordion title="What is MVC (Model-View-Controller) and how is it used in Node.js?">
    MVC separates your application into:

    * **Model**: Manages data and database operations
    * **View**: Renders UI (in REST APIs, often JSON)
    * **Controller**: Handles requests, uses Model to get data, and sends responses

    ## Example:

    ```javascript theme={null}
    // user.model.js
    export const User = mongoose.model('User', new Schema({ name: String }));

    // user.controller.js
    import { User } from './user.model.js';
    export const getUsers = async (req, res) => {
      const users = await User.find();
      res.json(users);
    };

    // user.routes.js
    router.get('/users', getUsers);
    ```

    ## Why:

    Encourages separation of concerns, clean testing, and reusability.

    ## Where/When:

    Common in Express-based web APIs and server-rendered apps.
  </Accordion>

  <Accordion title="How would you design a scalable microservices architecture in Node.js?">
    Microservices = small, independent services communicating via APIs or message queues.

    ## Key Components:

    * Each service has own database, own deployment
    * Communication via REST, gRPC, or message queues (e.g., RabbitMQ, Kafka)
    * Use API Gateway for centralized routing/auth

    ## Example Setup:

    ```
    user-service      → handles users
    order-service     → handles orders
    payment-service   → handles payments
    api-gateway       → routes and aggregates requests
    ```

    ## Example Communication:

    ```javascript theme={null}
    // user-service calls order-service via REST
    const axios = require('axios');
    const orders = await axios.get(`http://order-service/orders?userId=${userId}`);
    ```

    ## Why:

    * Independent scaling and deployment
    * Easier fault isolation
    * Better for large teams or multi-domain systems

    ## When/Where:

    Used in enterprise systems (e.g., eCommerce, SaaS) where modularity and scaling are critical.
  </Accordion>

  <Accordion title="How do microservices communicate with each other?">
    Node.js microservices can communicate via:

    | Type                           | Example                        | Use Case          |
    | ------------------------------ | ------------------------------ | ----------------- |
    | Synchronous (Request-Response) | REST, gRPC                     | Real-time data    |
    | Asynchronous (Event-driven)    | RabbitMQ, Kafka, Redis Pub/Sub | Decoupled systems |

    ## Asynchronous Messaging Example (RabbitMQ):

    ```javascript theme={null}
    const amqp = require('amqplib');

    (async () => {
      const conn = await amqp.connect('amqp://localhost');
      const channel = await conn.createChannel();
      await channel.assertQueue('orderQueue');
      channel.sendToQueue('orderQueue', Buffer.from('New order created'));
    })();
    ```

    ## Why:

    Async messaging improves resilience and fault tolerance.

    ## When/Where:

    Use async communication when loose coupling is desired (e.g., sending notifications after order creation).
  </Accordion>

  <Accordion title="Explain Repository Pattern and why it's useful">
    Repository Pattern abstracts database logic into a single layer, separating it from business logic.

    ## Example:

    ```javascript theme={null}
    // user.repository.js
    export class UserRepository {
      async findByEmail(email) {
        return User.findOne({ email });
      }
    }

    // user.service.js
    const repo = new UserRepository();
    const user = await repo.findByEmail(req.body.email);
    ```

    ## Why:

    * Makes business logic database-agnostic
    * Simplifies unit testing (mock repositories)
    * Promotes clean architecture

    ## When/Where:

    Used in large teams where database changes should not affect business logic.
  </Accordion>

  <Accordion title="What is Dependency Injection and how can it be applied in Node.js?">
    Dependency Injection (DI) means passing dependencies (services, repositories, etc.) into classes/functions instead of creating them inside.

    ## Example:

    ```javascript theme={null}
    class EmailService {
      send(email, msg) { console.log(`Email sent to ${email}`); }
    }

    class UserController {
      constructor(emailService) {
        this.emailService = emailService;
      }
      register(user) {
        this.emailService.send(user.email, "Welcome!");
      }
    }

    const emailService = new EmailService();
    const userController = new UserController(emailService);
    ```

    ## Why:

    * Enables loose coupling and easier testing
    * Supports inversion of control

    ## When/Where:

    Used in testable architectures, e.g., NestJS framework (which has DI built-in).
  </Accordion>

  <Accordion title="How do you handle configuration management in Node.js across environments?">
    Store configurations separately for each environment (dev, staging, prod).

    ## Example Structure:

    ```
    config/
     ┣ default.json
     ┣ development.json
     ┣ production.json
    ```

    Use libraries like `dotenv` or `config`.

    ## Example with dotenv:

    ```javascript theme={null}
    require('dotenv').config();
    console.log(process.env.DB_HOST);
    ```

    ## Why:

    * Keeps secrets out of source code
    * Easier environment portability

    ## Where/When:

    In CI/CD pipelines and multi-environment deployments (e.g., AWS, Docker).
  </Accordion>

  <Accordion title="What is a layered architecture in backend design?">
    Layered architecture separates the backend into logical layers — each with its responsibility.

    ## Typical Layers:

    1. **Presentation (Controller)** – Handles requests
    2. **Business (Service)** – Contains logic
    3. **Data (Repository)** – Handles persistence
    4. **Integration (External APIs)** – Handles external comms

    ## Example Flow:

    ```
    Controller → Service → Repository → Database
    ```

    ## Why:

    * Makes the system modular, testable, and maintainable

    ## Where:

    Used in enterprise backends and API-first architectures.
  </Accordion>

  <Accordion title="How would you handle versioning in REST APIs?">
    Versioning allows you to introduce new features without breaking old clients.

    ## Ways to Version:

    1. **URL-based**: `/api/v1/users`
    2. **Header-based**: `Accept: application/vnd.api.v2+json`
    3. **Query-based**: `/users?version=2`

    ## Example:

    ```javascript theme={null}
    app.use('/api/v1', v1Routes);
    app.use('/api/v2', v2Routes);
    ```

    ## Why:

    Maintains backward compatibility and smooth client migration.

    ## When/Where:

    Use when rolling out breaking API changes.
  </Accordion>

  <Accordion title="Explain how you'd implement CQRS (Command Query Responsibility Segregation)">
    CQRS separates read and write operations into different models/services.

    ## Example:

    ```javascript theme={null}
    // Command (write)
    POST /orders → creates order in DB

    // Query (read)
    GET /orders/:id → reads from optimized read model or cache
    ```

    ## Why:

    * Improves scalability (writes and reads can scale independently)
    * Enables event sourcing and audit trails

    ## Where/When:

    Used in financial, e-commerce, and high-scale event systems.
  </Accordion>

  <Accordion title="What are modules in Node.js and why are they important?">
    Modules in Node.js are reusable blocks of code that encapsulate functionality. They help in organizing code into manageable, independent components.

    ## Node.js supports three main types of modules:

    1. **Core Modules (built-in)** → e.g., fs, path, http
    2. **Local Modules** → custom files in your app
    3. **Third-party Modules** → installed from npm (e.g., express, lodash)

    ## Example:

    ```javascript theme={null}
    // math.js (Local module)
    function add(a, b) {
      return a + b;
    }
    module.exports = { add };

    // app.js
    const { add } = require('./math');
    console.log(add(5, 10));
    ```

    ## Why:

    To promote reusability and separation of concerns. Without modules, everything would live in one file, making maintenance and testing hard.

    ## When:

    Use modules when splitting logic — routes, services, utilities, models, etc.

    ## Where:

    Common in every medium to large-scale Node.js app, especially with MVC or layered architecture.
  </Accordion>

  <Accordion title="Explain the difference between CommonJS (require) and ES Modules (import)">
    | Feature    | CommonJS (require)       | ES Modules (import)                    |
    | ---------- | ------------------------ | -------------------------------------- |
    | Loading    | Synchronous              | Asynchronous                           |
    | Syntax     | `const x = require('x')` | `import x from 'x'`                    |
    | Scope      | Wrapped in function      | Strict top-level                       |
    | Default in | Node.js before v14       | Modern Node.js (with "type": "module") |

    ## Example:

    ```javascript theme={null}
    // CommonJS
    const express = require('express');

    // ES Module
    import express from 'express';
    ```

    ## Why:

    ESM is the modern standard (tree-shaking, async loading, static analysis).

    ## When:

    * Use CommonJS in legacy or mixed codebases
    * Use ESM for modern projects (especially with TypeScript or Next.js APIs)

    ## Where:

    Configured via package.json → `"type": "module"`
  </Accordion>

  <Accordion title="What is the difference between MVC and layered architecture in Node.js?">
    | Concept | MVC                        | Layered Architecture                  |
    | ------- | -------------------------- | ------------------------------------- |
    | Pattern | Model–View–Controller      | Request–Controller–Service–Repository |
    | Purpose | Web apps with UI           | APIs and backend systems              |
    | Focus   | Separation of UI and logic | Logical separation by responsibility  |

    ## Example Layered Architecture Flow:

    ```
    Request → Controller → Service → Repository → Database
    ```

    ```javascript theme={null}
    // userController.js
    const userService = require('../services/userService');
    exports.getUser = async (req, res) => {
      const user = await userService.getById(req.params.id);
      res.json(user);
    };

    // userService.js
    const userRepo = require('../repositories/userRepo');
    exports.getById = async (id) => await userRepo.findById(id);
    ```

    ## Why:

    Each layer has a single responsibility — easy to test and change independently.

    ## When:

    For scalable APIs and microservices.

    ## Where:

    Used in enterprise Node.js apps (Express, NestJS, Fastify-based systems).
  </Accordion>

  <Accordion title="How do you manage environment variables in Node.js?">
    Using dotenv or process.env to manage secrets and configurations per environment (dev, staging, production).

    ## Example:

    ```bash theme={null}
    # .env file
    PORT=5000
    DB_URI=mongodb://localhost:27017/mydb
    ```

    ```javascript theme={null}
    // config.js
    require('dotenv').config();
    module.exports = {
      port: process.env.PORT,
      db: process.env.DB_URI,
    };
    ```

    ## Why:

    Keeps sensitive data (like DB passwords, API keys) out of code.

    ## When:

    Always use environment variables for configuration.

    ## Where:

    * `process.env` → globally accessible
    * Used in CI/CD pipelines, Docker, Kubernetes secrets, etc.
  </Accordion>

  <Accordion title="What is dependency injection and why is it useful in Node.js architecture?">
    Dependency Injection (DI) is a design pattern where dependencies are injected into a module instead of being hardcoded inside it.

    ## Example:

    ```javascript theme={null}
    // Without DI:
    const userRepo = require('./userRepo');
    exports.getUser = () => userRepo.findAll();

    // With DI:
    module.exports = (userRepo) => ({
      getUser: () => userRepo.findAll(),
    });
    ```

    ## Why:

    * Makes testing easier (can inject mocks)
    * Improves flexibility and maintainability

    ## When:

    Used heavily in frameworks like NestJS or in test-driven architectures.

    ## Where:

    Service layers, repositories, utilities, or external integrations.
  </Accordion>

  <Accordion title="How do you handle circular dependencies in Node.js modules?">
    A circular dependency occurs when two modules depend on each other directly or indirectly.

    ## Example:

    ```javascript theme={null}
    // a.js
    const b = require('./b');
    module.exports = { name: 'A' };

    // b.js
    const a = require('./a');
    module.exports = { name: 'B' };
    ```

    This can cause incomplete exports or undefined values.

    ## Solution:

    1. Refactor shared logic into a new module
    2. Use dependency injection
    3. Lazy-load the dependency inside a function

    ```javascript theme={null}
    // a.js - Lazy loading solution
    function getB() {
      const b = require('./b');
      return b.name;
    }
    ```

    ## Why:

    To prevent runtime bugs due to incomplete module initialization.

    ## When:

    When modules reference each other's exports.

    ## Where:

    Common in large codebases with intertwined controllers/services.
  </Accordion>

  <Accordion title="What is the EventEmitter pattern and how is it used in Node.js?">
    EventEmitter is the **core pub/sub pattern** built into Node.js. Almost everything in Node -- HTTP servers, streams, file system watchers -- inherits from EventEmitter. Understanding it is essential because it is the foundation of Node's event-driven architecture.

    ## Core API:

    ```javascript theme={null}
    const EventEmitter = require('events');
    const emitter = new EventEmitter();

    // Subscribe to an event
    emitter.on('orderPlaced', (order) => {
      console.log(`Processing order ${order.id}`);
    });

    // Emit an event
    emitter.emit('orderPlaced', { id: 1, total: 99.99 });
    ```

    ## Real-world production use case -- decoupled business logic:

    ```javascript theme={null}
    // orderService.js
    class OrderService extends EventEmitter {
      async createOrder(data) {
        const order = await db.orders.create(data);
        this.emit('orderCreated', order);  // other services react
        return order;
      }
    }

    // In app setup:
    const orderService = new OrderService();
    orderService.on('orderCreated', (order) => emailService.sendConfirmation(order));
    orderService.on('orderCreated', (order) => inventoryService.reduceStock(order));
    orderService.on('orderCreated', (order) => analyticsService.track(order));
    ```

    **Key methods:**

    * `on(event, listener)` -- subscribe (alias: `addListener`)
    * `once(event, listener)` -- subscribe for one event only
    * `emit(event, ...args)` -- trigger all listeners for an event
    * `removeListener(event, listener)` -- unsubscribe
    * `setMaxListeners(n)` -- default is 10; exceeding it prints a memory leak warning

    **Production gotcha:** If you add listeners in a loop or on every request without removing them, you will hit the "MaxListenersExceededWarning" -- a classic memory leak pattern in Node.js.

    **What interviewers are really testing:** Whether you can use EventEmitter for architectural decoupling, not just event handling.

    **Red flag answer:** "EventEmitter is for custom events." Too vague -- misses that it is the backbone of Node's I/O model and can be used for service decoupling.

    **Follow-up:**

    1. How do you prevent memory leaks caused by forgotten event listeners?
    2. What is the difference between `on` and `once`? When would you use `once`?
    3. How does EventEmitter relate to Node.js streams?
  </Accordion>

  <Accordion title="How do you implement graceful shutdown in a Node.js server?">
    Graceful shutdown means **finishing in-flight requests and cleaning up resources** before the process exits, rather than abruptly killing connections. This is critical in production where a deploy or restart should not cause errors for active users.

    ## Production-grade implementation:

    ```javascript theme={null}
    const server = app.listen(3000);

    function gracefulShutdown(signal) {
      console.log(`Received ${signal}. Starting graceful shutdown...`);

      // 1. Stop accepting new connections
      server.close(() => {
        console.log('HTTP server closed');

        // 2. Close database connections
        mongoose.connection.close(false, () => {
          console.log('MongoDB connection closed');

          // 3. Close Redis connections
          redisClient.quit(() => {
            console.log('Redis connection closed');
            process.exit(0);
          });
        });
      });

      // 4. Force kill after timeout (prevent hanging)
      setTimeout(() => {
        console.error('Forcefully shutting down');
        process.exit(1);
      }, 10000); // 10 second timeout
    }

    process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
    process.on('SIGINT', () => gracefulShutdown('SIGINT'));
    ```

    **Why this matters in production:**

    * **Kubernetes** sends SIGTERM before killing a pod. Without graceful shutdown, active requests get 502 errors
    * **PM2** sends SIGINT before restarting. Without graceful shutdown, database connections may not close properly, causing connection pool exhaustion
    * **Load balancers** need time to drain connections from the old instance before routing to the new one

    **The order matters:**

    1. Stop accepting new connections (`server.close()`)
    2. Finish in-flight requests (they complete normally)
    3. Close external connections (DB, Redis, message queues)
    4. Exit the process

    **What interviewers are really testing:** Production maturity. This question separates developers who have deployed Node.js to production from those who only run `node app.js` locally.

    **Red flag answer:** "Just call `process.exit(0)`." This kills everything immediately, including in-flight requests and open database transactions.

    **Follow-up:**

    1. What signal does Kubernetes send before killing a pod, and how much time do you have to shut down?
    2. How do you handle long-running WebSocket connections during graceful shutdown?
    3. What happens if a database operation is mid-transaction when SIGTERM is received?
  </Accordion>

  <Accordion title="How do you organize routes in an Express application?">
    Split routes by feature or module to avoid one large routes file.

    ## Example:

    ```javascript theme={null}
    // routes/userRoutes.js
    const express = require('express');
    const router = express.Router();
    const userController = require('../controllers/userController');

    router.get('/', userController.getAllUsers);
    router.post('/', userController.createUser);

    module.exports = router;

    // app.js
    const express = require('express');
    const app = express();
    app.use('/users', require('./routes/userRoutes'));
    ```

    ## Why:

    Keeps routing organized and readable.

    ## When:

    As soon as routes exceed 4–5 endpoints.

    ## Where:

    Used in all Express/Fastify REST APIs.
  </Accordion>

  <Accordion title="What are 'config', 'utils', and 'helpers' folders used for?">
    | Folder  | Purpose                       | Example                            |
    | ------- | ----------------------------- | ---------------------------------- |
    | config  | Centralized configurations    | DB, environment setup              |
    | utils   | Reusable functions            | formatters, loggers, date handlers |
    | helpers | Request-specific helper logic | validation, response shaping       |

    ## Example:

    ```javascript theme={null}
    // utils/logger.js
    module.exports = (msg) => console.log(`[LOG]: ${msg}`);
    ```

    ## Why:

    Encourages DRY (Don't Repeat Yourself) coding.

    ## When:

    Used in any mid-size project to centralize repetitive logic.

    ## Where:

    Globally accessible via imports across layers.
  </Accordion>

  <Accordion title="How do you separate concerns in a Node.js microservice architecture?">
    In microservices:

    * Each service owns a single business domain
    * Communicates via APIs, queues, or message brokers (e.g., RabbitMQ, Kafka)
    * Uses its own database

    ## Example Architecture:

    ```
    /user-service
    /order-service
    /notification-service
    ```

    Each runs independently and communicates via REST or async queues.

    ## Why:

    To achieve scalability, fault isolation, and independent deployment.

    ## When:

    When the app grows large and needs distributed scaling.

    ## Where:

    Used in large enterprise systems (e.g., Uber, Netflix architectures).
  </Accordion>
</AccordionGroup>

<hr />

## 12. Node.js Testing and Debugging

<AccordionGroup>
  <Accordion title="Why is testing important in backend development, and what types of testing do you perform in Node.js projects?">
    Testing ensures your application works as expected, remains stable during code changes, and helps catch bugs early before deployment.

    ## Types of testing in Node.js:

    1. **Unit Testing** – Tests individual functions or modules
       * Tools: Jest, Mocha, Chai
       * Example: testing a utility function like `calculateTax()`

    2. **Integration Testing** – Tests multiple components working together
       * Example: testing API endpoints interacting with database and services

    3. **End-to-End (E2E) Testing** – Simulates real user scenarios
       * Tools: Supertest, Cypress

    4. **Regression Testing** – Ensures new code doesn't break existing functionality

    5. **Performance / Load Testing** – Evaluates API performance under stress
       * Tools: Artillery, K6

    ## Why:

    Improves code reliability and confidence in deployment.

    ## When:

    After each module development or before merging into main branch.

    ## Where:

    Applied across APIs, database queries, and business logic layers.
  </Accordion>

  <Accordion title="What is Unit Testing and how do you implement it in Node.js?">
    Unit testing focuses on testing individual functions or components in isolation.

    ## Why:

    To verify that each unit of your code performs as intended without depending on external systems.

    ## When:

    During development or before integration.

    ## Example using Jest:

    ```javascript theme={null}
    // tax.js
    function calculateTax(amount) {
      if (amount <= 0) return 0;
      return amount * 0.1;
    }
    module.exports = calculateTax;

    // tax.test.js
    const calculateTax = require('./tax');

    test('should calculate 10% tax', () => {
      expect(calculateTax(100)).toBe(10);
    });

    test('should return 0 for invalid amount', () => {
      expect(calculateTax(-50)).toBe(0);
    });
    ```

    ## Where:

    Stored inside a `__tests__` folder or with `.test.js` extension inside the same module directory.
  </Accordion>

  <Accordion title="How do you test API endpoints in a Node.js app?">
    Use Supertest (with Jest or Mocha) to test your Express APIs.

    ## Why:

    It performs real HTTP requests to your routes and verifies the response.

    ## Example:

    ```javascript theme={null}
    const request = require('supertest');
    const app = require('../app');

    describe('GET /users', () => {
      it('should return all users', async () => {
        const res = await request(app).get('/users');
        expect(res.statusCode).toEqual(200);
        expect(Array.isArray(res.body)).toBe(true);
      });
    });
    ```

    ## When:

    Run after every build or deploy via CI/CD pipelines.

    ## Where:

    Tests are usually stored in `/tests/api` or `/__integration__/`.
  </Accordion>

  <Accordion title="How do you mock external dependencies or services during testing?">
    Use mocking to isolate your code from external APIs, databases, or modules.

    ## Why:

    To ensure tests run fast, deterministically, and don't depend on network or environment.

    ## When:

    When your code calls APIs, databases, or third-party SDKs.

    ## Example using Jest Mocks:

    ```javascript theme={null}
    // userService.js
    const axios = require('axios');
    async function getUser(id) {
      const res = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`);
      return res.data;
    }
    module.exports = getUser;

    // userService.test.js
    jest.mock('axios');
    const axios = require('axios');
    const getUser = require('./userService');

    test('should return mocked user', async () => {
      axios.get.mockResolvedValue({ data: { id: 1, name: 'John' } });
      const user = await getUser(1);
      expect(user.name).toBe('John');
    });
    ```

    ## Where:

    In any module that uses third-party dependencies like AWS SDK, Stripe, or Axios.
  </Accordion>

  <Accordion title="How do you debug a Node.js application?">
    Debugging helps track down bugs, performance issues, and unexpected behaviors.

    ## Common methods:

    1. **Console logging**:
       Quick and easy but not ideal for large projects.
       ```javascript theme={null}
       console.log('User:', user);
       ```

    2. **Node Inspector / Chrome DevTools**:
       Run app with:
       ```bash theme={null}
       node --inspect app.js
       ```
       Then open `chrome://inspect` → Attach debugger → Add breakpoints.

    3. **VS Code Debugger**:
       Add a launch.json config:
       ```json theme={null}
       {
         "type": "node",
         "request": "launch",
         "program": "${workspaceFolder}/app.js"
       }
       ```

    4. **PM2 Logs**:
       For production debugging:
       ```bash theme={null}
       pm2 logs
       ```

    ## When:

    During development or after reproducing a bug reported from QA.

    ## Where:

    You can debug application logic, event loops, or async operations.
  </Accordion>

  <Accordion title="How do you handle errors gracefully in Node.js applications?">
    Use structured error handling so the system remains stable even when exceptions occur.

    ## Why:

    Uncaught exceptions can crash the server.

    ## Example (Async/Await):

    ```javascript theme={null}
    app.get('/user/:id', async (req, res, next) => {
      try {
        const user = await User.findById(req.params.id);
        if (!user) throw new Error('User not found');
        res.json(user);
      } catch (err) {
        next(err);
      }
    });

    // global error handler
    app.use((err, req, res, next) => {
      console.error(err.message);
      res.status(500).json({ error: err.message });
    });
    ```

    ## When:

    Apply globally via middleware for every route.

    ## Where:

    At controller level or in a centralized error handler.
  </Accordion>

  <Accordion title="What are some common debugging tools or libraries used in Node.js?">
    * **Node.js Inspector** – built-in debugger for step-through debugging
    * **Chrome DevTools** – UI-based debugging
    * **VS Code Debugger** – integrated IDE tool
    * **PM2** – process manager for logs and metrics
    * **Clinic.js** – performance profiler
    * **Winston / Pino** – structured logging libraries

    ## Why:

    They help in isolating performance bottlenecks, memory leaks, and runtime errors.

    ## Where:

    Use locally (VS Code/Chrome) or in production (PM2, Winston).
  </Accordion>

  <Accordion title="How do you ensure test coverage and integrate testing into CI/CD?">
    Test coverage measures how much of your code is executed during tests.

    ## Tool: Jest provides built-in coverage reports.

    ```bash theme={null}
    jest --coverage
    ```

    This outputs:

    ```
    Statements   : 92%
    Branches     : 85%
    Functions    : 90%
    Lines        : 93%
    ```

    ## CI/CD Integration (GitHub Actions example):

    ```yaml theme={null}
    name: Node.js CI
    on: [push]
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - run: npm install
          - run: npm test -- --coverage
    ```

    ## Why:

    Automatically ensures all commits pass tests before merging.

    ## When:

    Triggered on every pull request or push to main branch.
  </Accordion>

  <Accordion title="How do you debug a memory leak in Node.js?">
    Memory leaks occur when memory is allocated but never freed.

    ## Detection Steps:

    1. Monitor heap usage:
       ```javascript theme={null}
       setInterval(() => console.log(process.memoryUsage()), 5000);
       ```

    2. Use Chrome DevTools:
       * Run `node --inspect`
       * Open Heap Snapshots → Compare over time

    3. Use Clinic.js or Memwatch-next

    ## Common causes:

    * Global variables
    * Unclosed timers
    * Unreleased event listeners

    ## Fix:

    * Use WeakMap for temporary references
    * Remove listeners:
      ```javascript theme={null}
      emitter.removeAllListeners();
      ```
    * Close database connections
  </Accordion>
</AccordionGroup>

<hr />

## 13. Database Design

<AccordionGroup>
  <Accordion title="How do you decide between SQL and NoSQL for a project?">
    It depends on data structure, relationships, and query patterns.

    | SQL (Relational)                    | NoSQL (Document/Key-Value)        |
    | ----------------------------------- | --------------------------------- |
    | Structured schema (tables, columns) | Flexible schema (JSON, documents) |
    | Strong relationships (JOINs)        | Denormalized, nested data         |
    | ACID transactions                   | Eventual consistency              |
    | Example: PostgreSQL, MySQL          | Example: MongoDB, DynamoDB        |

    ## Example Use Cases:

    * **SQL**: Financial systems, HR platforms (strong relationships)
    * **NoSQL**: E-commerce product catalogs, social feeds (flexible schema)

    ## Why:

    SQL enforces strict integrity, NoSQL provides scalability.

    ## When:

    Choose SQL when data relations are strong; NoSQL for fast-growing, schema-less data.

    ## Where:

    SQL → transactional layer; NoSQL → analytics or caching layer.
  </Accordion>

  <Accordion title="Explain normalization and denormalization. When would you use each?">
    * **Normalization**: Process of organizing data to reduce redundancy and improve consistency
    * **Denormalization**: Combining related data into a single structure to improve read performance

    ## Example:

    **Normalized (two tables):**

    ```sql theme={null}
    Users: (id, name)
    Orders: (id, user_id, product)
    ```

    **Denormalized (single collection in MongoDB):**

    ```javascript theme={null}
    {
      "userId": 1,
      "name": "Ali",
      "orders": [
        { "product": "Laptop" },
        { "product": "Mouse" }
      ]
    }
    ```

    ## Why:

    Normalization improves consistency; denormalization improves read speed.

    ## When:

    Normalize for frequent writes, denormalize for heavy reads.

    ## Where:

    E.g., OLTP → normalized; OLAP/NoSQL → denormalized.
  </Accordion>

  <Accordion title="What is an index? How does it improve performance, and when can it hurt?">
    An index is a data structure (like a B-tree or hash) that allows fast lookups on columns or fields.

    ## Example (MongoDB & SQL):

    ```javascript theme={null}
    // MongoDB
    db.users.createIndex({ email: 1 });

    // SQL
    CREATE INDEX idx_email ON users(email);
    ```

    ## Why:

    It avoids full collection/table scans.

    ## When:

    Use on frequently filtered or sorted fields (like email, createdAt).

    ## Where:

    Use on read-heavy collections/tables.

    <Warning>
      Indexes slow down writes (inserts/updates) and increase memory usage. Avoid over-indexing — only index what you query often.
    </Warning>
  </Accordion>

  <Accordion title="Explain transactions in databases. How are they handled in Node.js?">
    A transaction ensures a group of operations succeeds or fails as one unit (ACID — Atomicity, Consistency, Isolation, Durability).

    ## Example (PostgreSQL with Sequelize):

    ```javascript theme={null}
    const t = await sequelize.transaction();

    try {
      await User.create({ name: 'Ali' }, { transaction: t });
      await Order.create({ userId: 1, product: 'Phone' }, { transaction: t });
      await t.commit();
    } catch (err) {
      await t.rollback();
    }
    ```

    ## Why:

    Prevents partial updates when one step fails.

    ## When:

    Use for multi-table or dependent operations (e.g., payments, inventory).

    ## Where:

    Implement in service layer functions handling multi-step DB operations.
  </Accordion>

  <Accordion title="How do you optimize slow database queries?">
    Step-by-step approach:

    1. Use `EXPLAIN` or `explain()` to inspect query execution plan
    2. Add proper indexes
    3. Avoid `SELECT *`; specify columns
    4. Paginate large queries
    5. Cache repetitive queries

    ## Example (MongoDB):

    ```javascript theme={null}
    db.orders.find({ status: 'completed' }).explain('executionStats');
    ```

    ## Example (Redis caching):

    ```javascript theme={null}
    const cached = await redis.get('orders');
    if (cached) return JSON.parse(cached);

    const data = await Order.find({ status: 'completed' });
    await redis.setEx('orders', 3600, JSON.stringify(data));
    ```

    ## Why:

    Optimized queries save cost and improve API response times.

    ## When:

    Apply during scaling or under heavy load.

    ## Where:

    Inside data-access layer (repositories).
  </Accordion>

  <Accordion title="What are database relationships and how do you handle them in Node.js?">
    Common types:

    * **One-to-One**: User ↔ Profile
    * **One-to-Many**: User → Orders
    * **Many-to-Many**: Students ↔ Courses

    ## Example (MongoDB - embedding vs referencing):

    ```javascript theme={null}
    // Referencing (normalized)
    const order = { userId: ObjectId("..."), product: "Laptop" };

    // Embedding (denormalized)
    const user = { name: "Ali", orders: [{ product: "Laptop" }] };
    ```

    ## Why:

    Embedding improves read speed; referencing saves space.

    ## When:

    Embed for frequent reads; reference for frequent writes.

    ## Where:

    Schema design phase, based on access patterns.
  </Accordion>

  <Accordion title="How do you handle pagination efficiently?">
    **Offset-based (SQL):**

    ```sql theme={null}
    SELECT * FROM orders LIMIT 10 OFFSET 20;
    ```

    **Cursor-based (MongoDB or large datasets):**

    ```javascript theme={null}
    db.orders.find({ _id: { $gt: lastId } }).limit(10);
    ```

    ## Why:

    Offset is simple but inefficient for large data; cursor-based is faster.

    ## When:

    Cursor-based for infinite scrolling or APIs.

    ## Where:

    Implement in API layer — `GET /orders?cursor=<id>`
  </Accordion>

  <Accordion title="What are database migrations and why are they important?">
    Migrations are version control for your database schema.

    ## Example (with Sequelize):

    ```bash theme={null}
    npx sequelize migration:generate --name add_isActive_to_users
    ```

    ## Example (migration file):

    ```javascript theme={null}
    export async function up(queryInterface, Sequelize) {
      await queryInterface.addColumn('Users', 'isActive', Sequelize.BOOLEAN);
    }
    ```

    ## Why:

    Ensures consistent schema across environments (dev, staging, prod).

    ## When:

    Whenever adding/removing/modifying columns or constraints.

    ## Where:

    Stored in `/migrations` folder, managed by ORM/CLI.
  </Accordion>

  <Accordion title="How do you scale databases in high-traffic applications?">
    Techniques:

    1. **Read replicas** — offload read traffic
    2. **Sharding** — partition data by key (e.g., userId)
    3. **Caching** — Redis/Memcached for frequent reads
    4. **Connection pooling** — reuse DB connections

    ## Example:

    ```javascript theme={null}
    const pool = new Pool({
      max: 10, // limit active connections
      idleTimeoutMillis: 30000,
    });
    ```

    ## Why:

    Prevents bottlenecks under high load.

    ## When:

    Beyond 10k+ users or concurrent reads.

    ## Where:

    Database + ORM configuration level.
  </Accordion>

  <Accordion title="How do you ensure data consistency in distributed systems?">
    Consistency ensures all services see the same data.

    ## Patterns:

    * **Two-phase commit (2PC)** for strict consistency
    * **Eventual consistency** for scalability
    * **Sagas pattern** for distributed transactions

    ## Example (Sagas):

    ```javascript theme={null}
    // Place order -> reduce stock -> charge payment
    // If payment fails -> rollback stock -> cancel order
    ```

    ## Why:

    Keeps data correct even across microservices.

    ## When:

    In event-driven or microservice architectures.

    ## Where:

    Implement at service orchestration level.
  </Accordion>

  <Accordion title="What are ACID and BASE principles?">
    | ACID (SQL)  | BASE (NoSQL)         |
    | ----------- | -------------------- |
    | Atomicity   | Basically Available  |
    | Consistency | Soft-state           |
    | Isolation   | Eventual consistency |
    | Durability  |                      |

    ## Why:

    ACID ensures reliable transactions; BASE ensures availability at scale.

    ## When:

    Use ACID for critical systems (banking), BASE for high-volume systems (social media).

    ## Where:

    Choose based on business priority: consistency vs availability.
  </Accordion>

  <Accordion title="What is the N+1 query problem and how do you solve it?">
    The N+1 query problem occurs when fetching a list of N items results in **1 query for the list + N additional queries** for related data. It is the single most common performance issue in backend applications.

    ## Example of the problem:

    ```javascript theme={null}
    // 1 query: get all 100 users
    const users = await User.find();

    // N queries: get orders for EACH user (100 more queries!)
    for (const user of users) {
      user.orders = await Order.find({ userId: user._id });
    }
    // Total: 101 queries for what should be 1-2 queries
    ```

    ## Solutions:

    **1. Population/Join (MongoDB `populate` or SQL JOIN):**

    ```javascript theme={null}
    // MongoDB - 2 queries total (1 for users, 1 for all their orders)
    const users = await User.find().populate('orders');

    // SQL - 1 query with JOIN
    SELECT users.*, orders.* FROM users LEFT JOIN orders ON users.id = orders.user_id;
    ```

    **2. Batch loading (DataLoader pattern from GraphQL):**

    ```javascript theme={null}
    // Instead of N individual queries, batch them:
    const userIds = users.map(u => u._id);
    const allOrders = await Order.find({ userId: { $in: userIds } });
    // Then distribute orders to their users in-memory
    ```

    **3. Aggregation pipeline (MongoDB):**

    ```javascript theme={null}
    db.users.aggregate([
      { $lookup: { from: "orders", localField: "_id", foreignField: "userId", as: "orders" } }
    ]);
    ```

    **Real-world impact:** A SaaS dashboard loading 50 customers with their orders, invoices, and activity logs could fire 200+ queries instead of 4. Response time goes from 50ms to 5 seconds.

    **What interviewers are really testing:** Whether you have profiled and optimized database queries in production.

    **Red flag answer:** Not knowing what N+1 is, or solving it with application-level caching instead of fixing the query pattern.

    **Follow-up:**

    1. How would you detect N+1 queries in a production Node.js application?
    2. Does MongoDB's `populate()` actually solve N+1, or does it just hide it? How many queries does it actually execute?
    3. How does the DataLoader pattern batch and deduplicate queries in a GraphQL API?
  </Accordion>

  <Accordion title="What is database connection pooling and why is it critical in Node.js?">
    Connection pooling maintains a **pool of reusable database connections** instead of creating a new connection for every request. Creating a database connection is expensive -- it involves TCP handshake, authentication, and SSL negotiation (\~20-100ms per connection).

    ## Without pooling (bad):

    ```javascript theme={null}
    // Every request creates and destroys a connection
    app.get('/users', async (req, res) => {
      const client = await MongoClient.connect(uri); // 50ms overhead
      const users = await client.db().collection('users').find().toArray();
      await client.close(); // connection destroyed
      res.json(users);
    });
    ```

    ## With pooling (good):

    ```javascript theme={null}
    // One pool shared across all requests
    const client = new MongoClient(uri, {
      maxPoolSize: 50,      // max concurrent connections
      minPoolSize: 10,      // keep warm connections ready
      maxIdleTimeMS: 30000, // close idle connections after 30s
    });

    await client.connect(); // one-time setup

    app.get('/users', async (req, res) => {
      // Reuses existing connection from pool (~0ms overhead)
      const users = await client.db().collection('users').find().toArray();
      res.json(users);
    });
    ```

    **Pool sizing formula (production rule of thumb):**
    For Node.js: `poolSize = (number of CPU cores * 2) + number of disks`

    * Too few connections: requests queue up waiting for a connection
    * Too many connections: database server is overwhelmed (MongoDB has a default 1024 connection limit)
    * A typical Node.js service with 4 cores should start with 10-20 connections

    **Why this is especially important in Node.js:**

    * Node.js handles thousands of concurrent requests with one thread
    * Each concurrent request that needs a DB query needs a connection
    * Without pooling, 1000 concurrent requests create 1000 connections -- most databases cannot handle this

    **What interviewers are really testing:** Production database management experience. Connection pool exhaustion is one of the most common production incidents.

    **Red flag answer:** "I just connect to the database when the app starts." This might work but shows no understanding of pool sizing, connection limits, or concurrent request handling.

    **Follow-up:**

    1. Your app starts throwing "connection pool exhausted" errors during peak traffic. How do you diagnose and fix it?
    2. How do you handle database connection pool in a serverless environment (Lambda, Vercel Functions)?
    3. What is the connection pool behavior difference between Mongoose and the native MongoDB driver?
  </Accordion>
</AccordionGroup>

<hr />

## 14. API Design & Best Practices

<AccordionGroup>
  <Accordion title="What are RESTful APIs and their main principles?">
    REST (Representational State Transfer) is an architectural style for building scalable web services that communicate over HTTP.

    ## Core Principles:

    1. **Statelessness** → Server doesn't store client state between requests
    2. **Uniform Interface** → Consistent structure for all endpoints (`/users`, `/products`)
    3. **Client-Server Separation** → Independent evolution of frontend & backend
    4. **Cacheable** → Responses can be cached for performance
    5. **Layered System** → Requests pass through intermediaries like load balancers or proxies

    ## Example:

    ```javascript theme={null}
    // RESTful Routes
    GET    /users          // Fetch users
    POST   /users          // Create user
    GET    /users/:id      // Get user by ID
    PUT    /users/:id      // Update user
    DELETE /users/:id      // Delete user
    ```

    ## Why:

    REST's simplicity makes it ideal for large-scale distributed systems. The uniform interface means any developer can understand your API without reading implementation code.

    ## When:

    Use for stateless communication (e.g., SaaS apps, mobile backends, third-party integrations). REST is the default choice for CRUD-heavy APIs.

    ## Where:

    Commonly implemented with Express.js, NestJS, or Fastify. Consumed by React/Next.js frontends, mobile apps, and other services.

    **Common REST anti-patterns to avoid:**

    * **Verb in the URL**: `/api/getUsers` or `/api/createUser` -- HTTP methods already convey the action
    * **Inconsistent naming**: `/api/Users` vs `/api/user-profiles` vs `/api/orders_list` -- pick one convention (plural nouns, kebab-case is standard)
    * **Returning 200 for everything**: Even errors return `200 OK` with `{ "error": true }` in the body. Use proper HTTP status codes
    * **No pagination**: Returning all 50,000 records on a list endpoint

    **What interviewers are really testing:** Whether you can design clean, predictable APIs and know the principles beyond just "GET/POST/PUT/DELETE."

    **Red flag answer:** Defining REST as "an API that uses HTTP methods" without mentioning statelessness, resource-based URLs, or the uniform interface principle.

    **Follow-up:**

    1. What makes an API truly "RESTful" vs just "REST-like"? What is the Richardson Maturity Model?
    2. How do you handle actions that do not map cleanly to CRUD? For example, "send a password reset email."
    3. What is HATEOAS and why is it rarely implemented in practice?
  </Accordion>

  <Accordion title="How would you design an API for scalability and maintainability?">
    Follow best practices:

    ## Use modular folder structure:

    ```
    src/
      controllers/
      routes/
      services/
      models/
      middlewares/
    ```

    1. Follow Controller-Service-Repository pattern
    2. Use async/await and central error handling
    3. Add pagination, filtering, sorting

    ## Example:

    ```javascript theme={null}
    // Controller
    export const getUsers = async (req, res, next) => {
      const { page = 1, limit = 10 } = req.query;
      const users = await userService.getAll({ page, limit });
      res.json(users);
    };
    ```

    ## Why:

    Separation of concerns ensures scalability and testability.

    ## When:

    For medium to large projects.

    ## Where:

    Apply across all route modules for consistency.
  </Accordion>

  <Accordion title="What's the difference between PUT and PATCH?">
    | Method | Purpose                     | Example                                 |
    | ------ | --------------------------- | --------------------------------------- |
    | PUT    | Replace the entire resource | `{ "name": "Ali", "email": "x@x.com" }` |
    | PATCH  | Update part of a resource   | `{ "email": "new@x.com" }`              |

    ## Example:

    ```javascript theme={null}
    app.patch('/users/:id', async (req, res) => {
      const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
      res.json(user);
    });
    ```

    ## Why:

    Use PATCH for partial updates to avoid overwriting data.

    ## When:

    Frontend sends only changed fields.

    ## Where:

    In APIs supporting user profile updates, etc.
  </Accordion>

  <Accordion title="How do you handle errors and validation in REST APIs?">
    Centralized error handling ensures cleaner code and consistent responses.

    ## Example:

    ```javascript theme={null}
    // Middleware
    function errorHandler(err, req, res, next) {
      res.status(err.status || 500).json({ message: err.message });
    }

    // Controller
    if (!email) throw { status: 400, message: 'Email is required' };

    // Validation (Zod / Joi / Express Validator):
    import { z } from 'zod';
    const userSchema = z.object({ email: z.string().email(), password: z.string().min(6) });
    userSchema.parse(req.body);
    ```

    ## Why:

    Prevents invalid or unsafe input.

    ## When:

    Before DB operations or external API calls.

    ## Where:

    Middleware or controller level.
  </Accordion>

  <Accordion title="How do you handle versioning in APIs?">
    API versioning ensures backward compatibility when updating endpoints.

    ## Methods:

    1. **URL versioning (most common):**
       ```
       /api/v1/users
       /api/v2/users
       ```

    2. **Header versioning:**
       ```
       Accept: application/vnd.myapp.v2+json
       ```

    ## Example:

    ```javascript theme={null}
    app.use('/api/v1', v1Routes);
    app.use('/api/v2', v2Routes);
    ```

    ## Why:

    Prevents breaking changes for existing clients.

    ## When:

    On major updates or endpoint restructuring.

    ## Where:

    Route definition layer.
  </Accordion>

  <Accordion title="How would you secure an API?">
    1. Authentication & Authorization (JWT, OAuth2)
    2. Input validation (prevent SQL/NoSQL injection)
    3. Rate limiting (prevent brute-force)
    4. CORS control
    5. HTTPS for encryption

    ## Example (rate limiting):

    ```javascript theme={null}
    import rateLimit from 'express-rate-limit';
    app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
    ```

    ## Why:

    Prevents abuse, leaks, and attacks.

    ## When:

    Always — security should be baked in early.

    ## Where:

    Applied globally or per route.
  </Accordion>

  <Accordion title="What are idempotent methods in REST APIs?">
    An idempotent method gives the same result even if called multiple times.

    | Method | Idempotent? | Example                        |
    | ------ | ----------- | ------------------------------ |
    | GET    | ✅ Yes       | Fetching user                  |
    | PUT    | ✅ Yes       | Updating same data             |
    | DELETE | ✅ Yes       | Deleting same resource again   |
    | POST   | ❌ No        | Creates a new record each time |

    ## Example:

    ```javascript theme={null}
    DELETE /users/5
    // Returns 204 No Content even if user was already deleted
    ```

    ## Why:

    Idempotency ensures reliability in retry scenarios.

    ## When:

    Especially in payment APIs or distributed systems.

    ## Where:

    Route and controller logic level.
  </Accordion>

  <Accordion title="How would you design pagination, filtering, and sorting?">
    ## Example:

    ```
    GET /products?page=2&limit=10&sort=price:desc&category=shoes
    ```

    ## Implementation:

    ```javascript theme={null}
    const { page = 1, limit = 10, sort, category } = req.query;
    const filter = category ? { category } : {};
    const products = await Product.find(filter)
      .skip((page - 1) * limit)
      .limit(limit)
      .sort(sort.replace(':', ' '));
    ```

    ## Why:

    Enhances performance and user experience.

    ## When:

    For list-based data (users, products, posts).

    ## Where:

    In every list API endpoint.
  </Accordion>

  <Accordion title="How do you document APIs effectively?">
    Use OpenAPI/Swagger for auto-generated documentation.

    ## Example:

    ```javascript theme={null}
    npm install swagger-ui-express swagger-jsdoc

    import swaggerUi from 'swagger-ui-express';
    import swaggerJsDoc from 'swagger-jsdoc';

    const specs = swaggerJsDoc({
      definition: { openapi: '3.0.0', info: { title: 'API Docs', version: '1.0.0' } },
      apis: ['./routes/*.js'],
    });
    app.use('/docs', swaggerUi.serve, swaggerUi.setup(specs));
    ```

    ## Why:

    Improves onboarding and collaboration with frontend teams.

    ## When:

    As soon as APIs are stable.

    ## Where:

    Separate `/docs` route.
  </Accordion>

  <Accordion title="How would you handle rate limiting and throttling?">
    **Rate limiting**: restricts number of requests per user/IP\
    **Throttling**: delays excessive requests

    ## Example (Redis-based):

    ```javascript theme={null}
    import rateLimit from 'express-rate-limit';
    app.use('/api', rateLimit({
      windowMs: 15 * 60 * 1000,
      max: 100,
      message: 'Too many requests, try again later.',
    }));
    ```

    ## Why:

    Prevents DDoS and API abuse.

    ## When:

    For login or public APIs.

    ## Where:

    At gateway or middleware layer.
  </Accordion>

  <Accordion title="What are some common API response codes and their meanings?">
    | Code | Meaning               | Use Case                |
    | ---- | --------------------- | ----------------------- |
    | 200  | OK                    | Successful GET          |
    | 201  | Created               | Resource created (POST) |
    | 204  | No Content            | Successful DELETE       |
    | 400  | Bad Request           | Validation error        |
    | 401  | Unauthorized          | Missing/invalid token   |
    | 403  | Forbidden             | Access denied           |
    | 404  | Not Found             | Resource doesn't exist  |
    | 500  | Internal Server Error | Unexpected error        |

    ## Example:

    ```javascript theme={null}
    res.status(201).json({ message: 'User created successfully' });
    ```

    ## Why:

    Clear status codes improve debugging and API usability.

    ## When:

    Always respond with meaningful HTTP codes.

    ## Where:

    Controller layer.
  </Accordion>

  <Accordion title="When would you choose GraphQL over REST?">
    | REST                 | GraphQL                      |
    | -------------------- | ---------------------------- |
    | Multiple endpoints   | Single endpoint `/graphql`   |
    | Fixed response shape | Client defines response      |
    | Over-fetching common | Fetch only needed fields     |
    | Simpler caching      | Complex but flexible queries |

    ## Example:

    ```graphql theme={null}
    // GraphQL query
    query {
      user(id: "1") {
        name
        posts {
          title
        }
      }
    }
    ```

    ## Why:

    GraphQL avoids under/over-fetching and gives the frontend team independence from the backend team's endpoint design. In a REST API, the frontend often needs to request 3-4 endpoints and stitch data together. GraphQL does this in one request.

    ## When:

    * **Choose GraphQL** for: complex UIs with diverse data needs (dashboards, social feeds), mobile apps where bandwidth is precious, or when multiple frontend teams consume the same API with different data requirements
    * **Choose REST** for: simple CRUD APIs, public APIs (REST is universally understood), webhooks, file uploads, or when caching is critical (REST + CDN is simpler than GraphQL caching)

    ## Where:

    Use Apollo Server, GraphQL Yoga, or Mercurius (Fastify) with Node.js. On the client, Apollo Client or urql.

    **The hidden cost of GraphQL:**

    * **Query complexity attacks**: Without depth limiting, a client can send a deeply nested query that takes down your server. Use `graphql-depth-limit` and `graphql-query-complexity`
    * **N+1 problem amplified**: Resolvers execute per-field, so a list of 100 users with their orders fires 100 individual order queries. DataLoader is mandatory
    * **Caching is harder**: REST endpoints are easily cached by CDNs (same URL = same response). GraphQL POST requests all go to `/graphql` with different bodies, making CDN caching ineffective
    * **Schema management overhead**: Maintaining a GraphQL schema, resolvers, and type generation (codegen) is more work than REST endpoints

    **What interviewers are really testing:** Whether you can make an informed technology choice based on project constraints, not just preference.

    **Red flag answer:** "GraphQL is better than REST because it avoids over-fetching." This ignores caching, complexity, the N+1 problem, and the operational overhead of GraphQL.

    **Follow-up:**

    1. How do you prevent malicious GraphQL queries from overloading your server?
    2. What is the DataLoader pattern and why is it essential for GraphQL performance?
    3. Can you use GraphQL and REST in the same project? When would you want to?
  </Accordion>
</AccordionGroup>

<hr />

## 15. Caching and Performance Optimization

<AccordionGroup>
  <Accordion title="What is caching and why is it important in Node.js applications?">
    Caching is the process of storing frequently accessed data in a fast-access storage layer (like memory) so that future requests for that data can be served faster.

    ## Why:

    * Reduces response time
    * Minimizes database load
    * Improves scalability and user experience

    ## When to use:

    When you have repetitive, read-heavy operations such as:

    * Fetching static product details
    * Returning popular posts
    * Computing costly aggregations

    ## Where:

    Typically used:

    * Between the API and the database
    * At CDN level for static assets
    * In-memory (e.g., Redis, Node cache) for API data

    ## Example:

    ```javascript theme={null}
    const express = require('express');
    const redis = require('redis');
    const fetch = require('node-fetch');

    const client = redis.createClient();
    const app = express();

    app.get('/posts', async (req, res) => {
      const cachedPosts = await client.get('posts');
      if (cachedPosts) return res.json(JSON.parse(cachedPosts));

      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const data = await response.json();

      client.setEx('posts', 3600, JSON.stringify(data)); // cache for 1 hour
      res.json(data);
    });
    ```

    <Info>
      The first request fetches data from the API, but subsequent ones serve from Redis memory, reducing external API calls.
    </Info>
  </Accordion>

  <Accordion title="What are different types of caching in Node.js?">
    ## 1. In-memory cache:

    * Stored in Node process memory using packages like node-cache or lru-cache
    * Fastest but not shared across multiple server instances
    * Best for: Single-instance apps, computed results

    ```javascript theme={null}
    const NodeCache = require("node-cache");
    const myCache = new NodeCache({ stdTTL: 600 });
    myCache.set("key", "value");
    console.log(myCache.get("key")); // 'value'
    ```

    ## 2. Distributed cache (Redis / Memcached):

    * External in-memory databases shared across multiple app instances
    * Best for: Scalable and load-balanced applications

    ## 3. Browser caching / CDN caching:

    * For static files like images, scripts, and CSS
    * Best for: Reducing load time for front-end users

    ## 4. Application-level caching:

    * Using HTTP headers like Cache-Control, ETag, or response-level caching middleware
  </Accordion>

  <Accordion title="How do you identify performance bottlenecks in a Node.js app?">
    By profiling and monitoring the app's runtime performance using tools such as:

    ## Node's built-in profiler:

    ```bash theme={null}
    node --inspect app.js
    ```

    Opens Chrome DevTools for debugging and profiling.

    ## Performance monitoring tools:

    * PM2 monitoring dashboard
    * New Relic, Datadog, or AppDynamics for production-level insights

    ## Steps to identify bottlenecks:

    1. Measure response time and CPU usage
    2. Analyze event loop lag (using clinic.js or node --inspect)
    3. Check for slow database queries and missing indexes
    4. Profile memory leaks via heap snapshots

    ## When:

    Always perform during load testing before production deployment.
  </Accordion>

  <Accordion title="How do you optimize a Node.js application for better performance?">
    ## 1. Use asynchronous code properly:

    Avoid blocking the event loop by using non-blocking async operations.

    ```javascript theme={null}
    // BAD: Blocking
    const fs = require('fs');
    const data = fs.readFileSync('file.txt');

    // GOOD: Non-blocking
    fs.readFile('file.txt', (err, data) => { ... });
    ```

    ## 2. Enable GZIP compression:

    Compress HTTP responses using middleware like compression.

    ```javascript theme={null}
    const compression = require('compression');
    app.use(compression());
    ```

    ## 3. Use Redis or in-memory cache:

    Cache frequent DB queries to reduce load.

    ## 4. Cluster your Node process:

    Utilize multiple CPU cores using cluster or PM2.

    ```javascript theme={null}
    const cluster = require('cluster');
    const os = require('os');

    if (cluster.isPrimary) {
      os.cpus().forEach(() => cluster.fork());
    } else {
      require('./server');
    }
    ```

    ## 5. Optimize database queries:

    Use proper indexes, projections, and pagination.

    ## 6. Use streaming for large data:

    Instead of loading entire data into memory.

    ```javascript theme={null}
    const fs = require('fs');
    fs.createReadStream('largeFile.txt').pipe(res);
    ```

    ## 7. Use load balancing & reverse proxies (Nginx):

    Helps distribute load across multiple Node instances.
  </Accordion>

  <Accordion title="What is Redis and how do you use it for caching in Node.js?">
    Redis is an in-memory data store that can be used for:

    * Caching responses
    * Session storage
    * Pub/Sub systems
    * Rate limiting

    ## Why Redis:

    * Very fast (stores data in RAM)
    * Persistent (can save snapshots to disk)
    * Supports TTL (time-to-live) expiration

    ## Example:

    ```javascript theme={null}
    const redis = require('redis');
    const client = redis.createClient();

    client.connect();

    async function getCachedUser(id) {
      const cachedUser = await client.get(`user:${id}`);
      if (cachedUser) return JSON.parse(cachedUser);

      const user = await getUserFromDatabase(id);
      await client.setEx(`user:${id}`, 600, JSON.stringify(user)); // cache 10min
      return user;
    }
    ```

    ## When:

    When your system frequently requests the same data from a slow data source like MongoDB or an external API.
  </Accordion>

  <Accordion title="What is event loop blocking and how does it impact performance?">
    Node.js is single-threaded, so any CPU-intensive task can block the event loop and delay other requests.

    ## Example of blocking:

    ```javascript theme={null}
    // BAD
    app.get('/heavy', (req, res) => {
      let sum = 0;
      for (let i = 0; i < 1e9; i++) sum += i; // blocks everything
      res.send('Done');
    });
    ```

    ## Fix:

    Use worker threads or child processes for CPU-heavy operations.

    ```javascript theme={null}
    const { Worker } = require('worker_threads');
    app.get('/heavy', (req, res) => {
      const worker = new Worker('./heavyTask.js');
      worker.on('message', msg => res.send(msg));
    });
    ```
  </Accordion>

  <Accordion title="How do you handle rate limiting and throttling for performance?">
    Rate limiting ensures a user doesn't overwhelm the server with too many requests in a short period.

    ## When to use:

    For APIs prone to abuse — login, search, or payment endpoints.

    ## Example using express-rate-limit:

    ```javascript theme={null}
    const rateLimit = require('express-rate-limit');

    const limiter = rateLimit({
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100,
    });

    app.use(limiter);
    ```

    <Note>
      You can also store rate limit counters in Redis for distributed environments.
    </Note>
  </Accordion>

  <Accordion title="How do you measure memory usage and detect memory leaks in Node.js?">
    You can monitor heap usage using:

    ```javascript theme={null}
    console.log(process.memoryUsage());
    ```

    or by using Chrome DevTools:

    * Run app with `node --inspect`
    * Open `chrome://inspect`
    * Take Heap Snapshots and compare over time

    ## When leaks occur:

    * Global variables not freed
    * Large cached data without TTL
    * Event listeners not removed

    ## Where to fix:

    Ensure proper cleanup using:

    ```javascript theme={null}
    emitter.removeAllListeners();
    cache.del('largeKey');
    ```
  </Accordion>
</AccordionGroup>

## Advanced Scenario-Based Questions

These questions simulate real production incidents and architectural decisions that separate candidates who have actually built and operated MERN applications at scale from those who have only completed tutorials.

<AccordionGroup>
  <Accordion title="Scenario 1: MongoDB Query Performance Collapse at Scale">
    **Scenario:** Your e-commerce platform runs on MongoDB. The product catalog has 12 million documents. A developer added a new "search by tags + price range + rating" feature last week. Since launch, the `/api/products/search` endpoint has degraded from 80ms to 6.2 seconds at p95. The collection has individual indexes on `tags`, `price`, and `rating`. CPU on your Atlas M40 cluster is pegged at 92%. The PM is asking why search is broken and wants it fixed by EOD. Walk me through your diagnosis and fix.

    **What weak candidates say:**
    "I'd add more indexes or increase the server size. Maybe we need to shard the collection."

    **What strong candidates say:**

    * The core issue is almost certainly **index intersection inefficiency**. MongoDB *can* combine multiple single-field indexes via index intersection, but it is wildly unpredictable and almost always slower than a proper compound index for multi-field queries. With 12M documents, the query planner is likely doing a collection scan or picking one index and then scanning millions of results for the other predicates.
    * **Step 1 - Confirm with `explain("executionStats")`**: Run the exact query the API fires with `.explain("executionStats")` and look at `totalDocsExamined` vs `totalKeysExamined` vs `nReturned`. If `totalDocsExamined` is in the millions but `nReturned` is in the hundreds, you have an index selectivity problem.
    * **Step 2 - Check with `$indexStats`**: Run `db.products.aggregate([{$indexStats: {}}])` to see which indexes are actually being used and how often. Bet the compound query is falling back to a single-field index scan.
    * **Step 3 - Build a compound index**: Create `db.products.createIndex({tags: 1, rating: -1, price: 1})` putting the **equality match field first** (`tags`), then the **sort/range field** (`rating` descending since users want highest first), then the secondary range field (`price`). This follows the ESR rule: Equality, Sort, Range.
    * **Step 4 - Drop the redundant single-field indexes** on `tags` and `rating` (the compound index covers those prefixes). Keep the `price` index only if other queries use it in isolation.
    * **Step 5 - Monitor with Atlas Performance Advisor** or `db.currentOp()` for slow queries after deployment. Target should be under 50ms at p95.
    * **Real-world gotcha**: Building an index on 12M docs will lock writes if you use foreground indexing. Always use `background: true` in older MongoDB versions. In MongoDB 4.2+ index builds are hybrid by default, but they still consume I/O. Schedule it during low-traffic hours or use a rolling index build across replica set members.
    * The sharding suggestion is a red flag at this scale. 12M documents is well within a single replica set capability. Sharding adds massive operational complexity and should only be considered when you are past several hundred million documents or your working set exceeds available RAM.

    **Follow-up:** How would your indexing strategy change if the `tags` field is an array with an average of 8 tags per product?

    **Follow-up:** The fix worked but the PM now wants full-text search with typo tolerance across product names and descriptions. Do you keep this in MongoDB or reach for something else? What are the trade-offs of MongoDB Atlas Search vs Elasticsearch vs Meilisearch?

    **Follow-up:** You discover that 40% of your queries are range queries on `price` alone without `tags`. How do you handle index design when different query patterns compete for optimization?
  </Accordion>

  <Accordion title="Scenario 2: React Component Re-renders Destroying Frame Rate">
    **Scenario:** Your team built a real-time dashboard in React that displays 200 rows of financial data updating via WebSocket every 500ms. Users report the UI is "janky" and unresponsive. React DevTools Profiler shows the entire table re-renders on every WebSocket message, even though each message only updates 3-5 rows. Each render cycle takes 180ms, well above the 16ms budget for 60fps. The component tree is: `Dashboard` then `DataTable` then `DataRow` (x200). How do you fix this?

    **What weak candidates say:**
    "I'd use `React.memo` on everything and add `useMemo` and `useCallback` everywhere."

    **What strong candidates say:**

    * Blanket `React.memo` is the spray-and-pray approach. It helps, but without understanding *why* things re-render, you will just shift the bottleneck. Here is a systematic approach:
    * **Root cause diagnosis**: The WebSocket handler likely sets state at the `Dashboard` level with something like `setRows(newRows)`, which replaces the entire array reference. Even if only 3 rows changed, React sees a new array and re-renders everything downstream.
    * **Fix 1 - Normalize state and update surgically**: Instead of storing rows as an array, use a `Map` or object keyed by row ID. When a WebSocket message arrives, only update the specific rows that changed:

    ```javascript theme={null}
    // Instead of: setRows(allNewRows)
    // Do this:
    const handleWSMessage = useCallback((updates) => {
      setRowMap(prev => {
        const next = new Map(prev);
        updates.forEach(u => next.set(u.id, u));
        return next;
      });
    }, []);
    ```

    * **Fix 2 - `React.memo` on `DataRow` with proper comparison**: Wrap `DataRow` in `React.memo` but ensure props are stable. If you pass callbacks, they must be wrapped in `useCallback`. If you pass objects, they need referential stability.
    * **Fix 3 - Virtualization**: 200 rows is borderline, but if each row has complex cells, use `react-window` or `@tanstack/virtual`. Only render the \~20 rows visible in the viewport. This alone can cut render time by 90%.
    * **Fix 4 - Decouple subscription from React state**: For truly high-frequency updates, consider using a `useRef` + `requestAnimationFrame` pattern where the WebSocket writes to a ref and a rAF loop reads from it to batch visual updates. Or use a state manager like Zustand which allows component-level subscriptions where each `DataRow` subscribes to only its own slice of data.
    * **Measurement**: After each fix, check the Profiler "Highlight updates when components render" and the Performance tab frame rate graph. Target: render time under 8ms to leave headroom for browser paint.
    * **What to avoid**: `shouldComponentUpdate` with deep comparison on 200 rows because the comparison cost itself becomes the bottleneck. Also avoid `JSON.stringify` comparisons. That is O(n) on object size for every render cycle.

    **Follow-up:** The product team now wants to add column sorting and filtering on top of the real-time updates. How do you keep derived state (sorted/filtered view) in sync with live updates without re-sorting on every WebSocket tick?

    **Follow-up:** One developer suggests moving the entire table to canvas rendering with something like `react-konva`. When would canvas-based rendering actually make sense over DOM-based React rendering?

    **Follow-up:** How would you approach this differently if you were using React Server Components and the data needed to be real-time?
  </Accordion>

  <Accordion title="Scenario 3: Node.js Memory Leak in Production">
    **Scenario:** Your Express API server runs in a Docker container with a 512MB memory limit. Monitoring shows RSS memory climbing steadily from 180MB at deploy to 480MB over 72 hours, at which point the container OOM-kills and restarts. There are no obvious errors in logs. The app serves \~2000 req/s. This started happening after a recent release that added a "user activity tracking" middleware. How do you find and fix the leak?

    **What weak candidates say:**
    "I'd increase the container memory or add more replicas. Maybe restart the container on a schedule."

    **What strong candidates say:**

    * Periodic restarts are a band-aid that masks the root cause. Here is a systematic approach:
    * **Step 1 - Confirm it is a heap leak, not native memory**: Run `process.memoryUsage()` on a timer and log `heapUsed`, `heapTotal`, `rss`, and `external`. If `heapUsed` grows linearly, it is a JS heap leak. If `rss` grows but `heapUsed` is stable, it is a native addon, Buffer, or stream leak which is a different debugging path entirely.
    * **Step 2 - Take heap snapshots in production**: Use the `--inspect` flag or `v8.writeHeapSnapshot()` triggered via a debug endpoint (protected behind auth). Take one snapshot at startup and another after 24 hours. Load both into Chrome DevTools Memory tab and use the "Comparison" view to see what objects accumulated.
    * **Step 3 - The "activity tracking" middleware is the prime suspect**. Common leak patterns in middleware:
      * **Closures capturing request objects**: If the middleware stores `req` or `res` references in a module-level array, Map, or Set for later processing, and those references are never cleaned up.
      * **Event listeners accumulating**: If it attaches listeners to a shared EventEmitter on every request without removing them. Node will warn with "MaxListenersExceededWarning" but check if this warning was suppressed with `setMaxListeners(0)`, which is a classic antipattern.
      * **Unbounded in-memory cache**: If it caches user activity data in a plain object or Map without TTL or size limits.
    * **Step 4 - Likely fix**: Based on the middleware pattern, look for something like:

    ```javascript theme={null}
    // THE LEAK - module-level Map that grows forever
    const activityLog = new Map();

    app.use((req, res, next) => {
      const entry = { user: req.userId, path: req.path, time: Date.now() };
      activityLog.set(req.requestId, entry);
      // BUG: Nothing ever calls activityLog.delete()
      next();
    });
    ```

    * **Fix**: Either flush to database/Redis periodically and clear the Map, use an LRU cache with a max size (`lru-cache` package), or better yet, do not accumulate in memory at all. Write directly to a log stream or message queue.
    * **Step 5 - Verify the fix**: Deploy and watch the memory graph. Healthy Node apps should have a sawtooth pattern (heap grows, GC collects, drops back) rather than a linear climb.
    * **Production tooling to set up**: Use `clinic.js` (`clinic doctor` and `clinic heap`) for automated analysis. In production, add a `/debug/memory` endpoint that returns `process.memoryUsage()` and trigger `global.gc()` (with `--expose-gc` flag) to differentiate between "has not GC'd yet" and "cannot GC."

    **Follow-up:** The heap snapshot shows 800,000 retained `IncomingMessage` objects. But the middleware does not explicitly store `req`. What other patterns could cause request objects to be retained?

    **Follow-up:** You fixed the leak, but now you notice the GC pause times spike to 200ms every few minutes, causing p99 latency spikes. How do you tune V8 garbage collection for a high-throughput API server?

    **Follow-up:** How would you set up proactive memory leak detection in your CI/CD pipeline so this does not reach production again?
  </Accordion>

  <Accordion title="Scenario 4: Express API Security Breach Post-Mortem">
    **Scenario:** Your security team discovered that an attacker accessed 15,000 user records through your Express API. The logs show the attacker made requests to `/api/users?role=admin` and `/api/users/../../etc/passwd`. Your API has JWT authentication but no further authorization layer. The team asks you to do a post-mortem and harden the API. Walk through your analysis and remediation plan.

    **What weak candidates say:**
    "I'd add input validation and make sure the JWT is checked on every route."

    **What strong candidates say:**

    * This breach has at least three distinct vulnerabilities that need separate fixes. Here is the breakdown of each attack vector:
    * **Vulnerability 1 - Broken Access Control (BOLA/IDOR)**: The `/api/users?role=admin` endpoint likely returns all users matching the query without checking whether the *requesting user* has permission to see those records. This is OWASP #1 Broken Access Control. The JWT proves *who* you are (authentication) but nothing checks *what you are allowed to access* (authorization).
      * **Fix**: Implement authorization middleware that checks the requesting user role/permissions before executing queries. Never trust query parameters for access control:

    ```javascript theme={null}
    // BEFORE (vulnerable)
    app.get('/api/users', authenticate, async (req, res) => {
      const users = await User.find(req.query); // attacker controls the query!
      res.json(users);
    });

    // AFTER (hardened)
    app.get('/api/users', authenticate, authorize('admin'), async (req, res) => {
      const allowedFilters = pick(req.query, ['name', 'department']);
      const users = await User.find(allowedFilters).select('-password -ssn -resetToken');
      res.json(users);
    });
    ```

    * **Vulnerability 2 - Path Traversal**: The `/api/users/../../etc/passwd` request is a classic path traversal attack. This suggests the app is using a user-supplied parameter to construct file paths or that the router is not sanitizing path parameters.
      * **Fix**: Never construct file paths from user input. If you must, use `path.resolve()` and verify the result stays within an allowed directory. Also, add `helmet` middleware which sets security headers, and use `express-mongo-sanitize` to prevent NoSQL injection via query parameter manipulation.
    * **Vulnerability 3 - Mass Assignment / Query Injection**: The fact that `req.query` is passed directly to `User.find()` means an attacker can inject arbitrary MongoDB operators like `{"role": {"$ne": null}}` to dump all records.
      * **Fix**: Whitelist allowed query fields. Never pass raw `req.query` or `req.body` to database operations. Use a validation library like `joi` or `zod`:

    ```javascript theme={null}
    const searchSchema = z.object({
      name: z.string().optional(),
      department: z.string().optional(),
      page: z.number().int().positive().default(1),
      limit: z.number().int().min(1).max(100).default(20),
    });
    ```

    * **Broader hardening checklist**:
      * Add rate limiting per user/IP (`express-rate-limit` + Redis store for distributed)
      * Implement request payload size limits (`express.json({limit: '10kb'})`)
      * Add CORS configuration restricted to your frontend domains
      * Enable security headers via `helmet()`
      * Log all access with correlation IDs for forensic analysis
      * Add field-level projection so you never return `password`, `resetToken`, `__v` fields
      * Implement API response pagination to prevent bulk data extraction
      * Set up anomaly detection: alert when a single user requests >100 records/minute

    **Follow-up:** The security team asks you to implement row-level security so users can only access records they own, except admins who can see everything. How do you architect this in Express + MongoDB without scattering authorization checks across every route handler?

    **Follow-up:** How would you handle API versioning in this hardening effort? Some mobile clients are on the old, vulnerable API version and cannot update immediately.

    **Follow-up:** The attacker used a leaked JWT that was valid for 30 days. How do you implement JWT revocation without losing the stateless benefit of JWTs?
  </Accordion>

  <Accordion title="Scenario 5: Full-Stack Debugging — The Phantom 500 Error">
    **Scenario:** Users are reporting intermittent 500 errors on your MERN application checkout flow. It happens maybe 1 in 50 requests. Your stack: React frontend, Express API, MongoDB with Mongoose, deployed on AWS ECS behind an ALB. The error does not reproduce locally. Logs show `MongoServerError: connection pool was cleared` at random intervals. Your APM (Datadog) shows p99 latency spikes correlating with the errors. Walk me through your debugging approach.

    **What weak candidates say:**
    "I'd check the MongoDB connection string and maybe increase the connection pool size."

    **What strong candidates say:**

    * Intermittent errors that do not reproduce locally are almost always infrastructure or connection management issues. The `connection pool was cleared` error is a dead giveaway. This means Mongoose connection pool detected a problem with the MongoDB server and dropped all connections, forcing reconnection. Here is a systematic approach:
    * **Step 1 - Check MongoDB health**: Look at Atlas metrics (or your MongoDB monitoring) for the exact timestamps of the errors. Look for:
      * **Primary elections**: If a replica set member steps down and a new primary is elected, all connections to the old primary are terminated. This causes exactly this error pattern.
      * **Network blips**: Transient network issues between ECS and MongoDB. Check AWS CloudWatch for ENI errors, NAT gateway timeouts, or VPC flow log anomalies.
      * **Maintenance windows**: Atlas performs maintenance that can trigger rolling restarts.
    * **Step 2 - Check Mongoose connection settings**: The default Mongoose connection config is often too aggressive on timeouts:

    ```javascript theme={null}
    // Resilient connection config
    mongoose.connect(uri, {
      maxPoolSize: 50,
      minPoolSize: 10,
      serverSelectionTimeoutMS: 5000,
      heartbeatFrequencyMS: 10000,
      retryWrites: true,
      retryReads: true,
      w: 'majority',
      socketTimeoutMS: 45000,
    });
    ```

    * **Step 3 - Implement retry logic at the application layer**: MongoDB driver v4+ has built-in `retryWrites` and `retryReads`, but Mongoose operations can still fail on pool clears. Wrap critical operations with retry logic:

    ```javascript theme={null}
    async function withRetry(operation, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        try {
          return await operation();
        } catch (err) {
          if (i === maxRetries - 1) throw err;
          if (err.message.includes('pool was cleared') ||
              err.message.includes('topology was destroyed')) {
            await new Promise(r => setTimeout(r, 100 * Math.pow(2, i)));
            continue;
          }
          throw err; // non-retryable error
        }
      }
    }
    ```

    * **Step 4 - Add connection event monitoring**:

    ```javascript theme={null}
    mongoose.connection.on('disconnected', () => logger.warn('MongoDB disconnected'));
    mongoose.connection.on('reconnected', () => logger.info('MongoDB reconnected'));
    mongoose.connection.on('error', (err) => logger.error('MongoDB error', err));
    ```

    * **Step 5 - Check ECS task networking**: If ECS tasks are cycling (deploys, autoscaling), new tasks might spike connection count. With 10 ECS tasks each opening 50 connections, that is 500 connections to MongoDB. Check if you are hitting Atlas connection limits.
    * **The real fix** is usually a combination: resilient connection config, retry logic for transient errors, proper error handling in Express that returns 503 (Service Unavailable) with a `Retry-After` header instead of 500, and client-side retry logic in the React app for checkout (with idempotency keys to prevent double-charging).

    **Follow-up:** The checkout flow involves creating an order, charging a payment, and updating inventory across three collections. How do you handle the case where the payment succeeds but the MongoDB connection drops before the order is saved?

    **Follow-up:** You notice the connection pool clear events always happen at exactly the same time each day. What would that suggest, and how would you confirm?

    **Follow-up:** How would you implement idempotency keys end-to-end from the React frontend through Express to MongoDB to prevent duplicate orders during retries?
  </Accordion>

  <Accordion title="Scenario 6: React State Management Meltdown">
    **Scenario:** You inherited a React application where the previous team used Redux for everything including form inputs, modal open/close state, hover states, and API loading states. The Redux store has 47 reducers. Every keystroke in a form dispatches an action, runs through all middleware, and triggers connected component re-renders across the app. The Redux DevTools extension crashes the browser when opened. The team wants to "fix state management." How do you approach this?

    **What weak candidates say:**
    "I'd rewrite everything to use React Context or switch to Zustand. Redux is overkill for most apps."

    **What strong candidates say:**

    * The problem is not Redux itself. It is that everything was put in Redux regardless of whether it belongs there. The fix is **state colocation**, not a wholesale migration. Here is the approach:
    * **Categorize state by scope and lifespan**:
      * **Local UI state** (modal open/close, hover, form inputs, accordions): Move to `useState` / `useReducer` in the component that owns it. This is the biggest win. It eliminates 60-70% of the Redux noise immediately.
      * **Shared client state** (current user, theme, feature flags): Keep in a lightweight global store. Could stay in Redux or move to Zustand/Jotai.
      * **Server state** (API data, loading, error states): Move to React Query or SWR. This alone eliminates the need for most async Redux middleware (`redux-thunk` / `redux-saga`).
      * **URL state** (pagination, filters, search terms): Move to URL search params with `useSearchParams()`. This makes the state shareable and bookmarkable.
    * **Migration strategy (incremental, not big-bang)**:
      * **Week 1**: Install React Query. Migrate the 3 most-used API data flows. Delete those reducers. Measure bundle size and render performance improvement.
      * **Week 2-3**: Audit all 47 reducers. Tag each as "local", "shared", or "server". Create a spreadsheet tracking migration status.
      * **Week 4-6**: Migrate local state out of Redux, feature by feature. Each PR should remove one reducer and be independently deployable.
      * **Week 7-8**: Evaluate what is left in Redux. If it is \<5 reducers of genuinely shared client state, keep Redux (or switch to Zustand for simplicity).
    * **Form state specifically**: For the form keystroke problem, use `react-hook-form` which keeps form state in refs (not React state), so inputs do not trigger re-renders at all:

    ```jsx theme={null}
    const { register, handleSubmit } = useForm();
    // Each keystroke updates a ref, not state — zero re-renders
    <input {...register('email')} />
    ```

    * **What to avoid**: Rewriting everything at once. Teams have spent 3 months on a "state management rewrite" that introduces as many bugs as it fixes. The incremental approach lets you ship improvements weekly and catch regressions early.
    * **Metrics to track**: Time-to-interactive, bundle size (Redux + middleware can be 30-40KB), render count per user action (measure in React Profiler), and developer velocity (how fast can new features be built).

    **Follow-up:** The team pushes back and says "Context is simpler than Redux." How do you explain to them that React Context has its own re-render problems and is not a state management solution?

    **Follow-up:** After migrating API state to React Query, the team notices stale data issues where one user updates a record but another user screen still shows the old data. How do you handle cache invalidation across multiple related queries?

    **Follow-up:** Some of the Redux middleware handles complex business logic like "if the user adds item X to cart, check inventory, apply discount rules, and suggest complementary products." Where does this logic live after the migration?
  </Accordion>

  <Accordion title="Scenario 7: Deploying MERN to Production — Everything Goes Wrong">
    **Scenario:** You are deploying a MERN application for the first time to production. The stack: React (Vite build), Express API, MongoDB Atlas, deployed on a single AWS EC2 instance with Nginx as reverse proxy. The deployment "works" but you discover: (1) The React app shows a blank white page on some routes when refreshed, (2) API responses are slow despite fast local performance, (3) Environment variables like `VITE_API_URL` are undefined in the built frontend, and (4) CORS errors appear when the frontend calls the API. Diagnose all four issues.

    **What weak candidates say:**
    "I'd check the console for errors. Maybe it's a CORS configuration issue."

    **What strong candidates say:**

    * These are four distinct issues that every MERN developer hits on their first real deployment. Addressing each:
    * **Issue 1 - Blank page on route refresh**: This is the classic SPA routing problem. When the user is on `/dashboard/settings` and refreshes, Nginx tries to serve a file at that path, which does not exist. Nginx returns 404 instead of serving `index.html` and letting React Router handle it.
      * **Fix** — Add a catch-all in Nginx:

    ```nginx theme={null}
    location / {
      root /var/www/frontend/dist;
      try_files $uri $uri/ /index.html;
    }
    ```

    * **Issue 2 - Slow API responses**: On EC2, the Express server connects to MongoDB Atlas over the public internet instead of a local connection. Each query has an added 20-50ms network round trip. Also, if the EC2 instance is in `us-east-1` but the Atlas cluster is in `us-west-2`, you are adding cross-region latency.
      * **Fix**: Enable VPC Peering between your AWS VPC and MongoDB Atlas. Ensure both are in the same region. Also enable connection pooling in Mongoose (default `maxPoolSize` is 100, which is fine) and add response compression:

    ```javascript theme={null}
    const compression = require('compression');
    app.use(compression()); // gzip responses — 60-80% size reduction for JSON
    ```

    * **Issue 3 - `VITE_API_URL` undefined**: Vite environment variables are **statically replaced at build time**, not read at runtime. If the `.env.production` file was not present during `vite build`, or if the variable does not start with `VITE_`, it will not be embedded in the bundle.
      * **Fix**: Ensure `.env.production` exists with `VITE_API_URL=https://api.yourdomain.com` before running `vite build`. Verify with `grep VITE_API_URL dist/assets/*.js` after build. For dynamic runtime config, use a `window.__CONFIG__` approach by injecting a script tag or serving a `/config.json` endpoint.
    * **Issue 4 - CORS errors**: The frontend is served from `https://app.yourdomain.com` but makes API calls to `https://api.yourdomain.com` (different subdomain = different origin). The Express API is not sending the right CORS headers.
      * **Fix**:

    ```javascript theme={null}
    const cors = require('cors');
    app.use(cors({
      origin: ['https://app.yourdomain.com'],
      credentials: true, // if using cookies/sessions
      methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
    }));
    ```

    * **Better approach**: Configure Nginx to proxy `/api/*` to the Express server so both frontend and API are served from the same origin, eliminating CORS entirely:

    ```nginx theme={null}
    location /api/ {
      proxy_pass http://localhost:3001/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
    ```

    * **Bonus production hardening**: Enable Nginx rate limiting, add `pm2` or `systemd` to keep the Node process alive, set `NODE_ENV=production` (Express enables view caching, reduces verbose errors), configure SSL with Let's Encrypt/Certbot, and add health check endpoints.

    **Follow-up:** The PM asks you to set up zero-downtime deployments for this single EC2 instance. Is it possible without adding more servers? How?

    **Follow-up:** You move to containerized deployment with Docker. The React build step takes 4 minutes. How do you optimize the Dockerfile for faster builds and smaller image size?

    **Follow-up:** Traffic grows 10x and the single EC2 instance cannot keep up. What is your migration path: ECS, EKS, or a PaaS like Railway/Render? What factors drive this decision?
  </Accordion>

  <Accordion title="Scenario 8: MongoDB Data Modeling Disaster">
    **Scenario:** Your social media app stores posts with comments embedded in the post document. It worked fine at launch. Now, six months in, some viral posts have 50,000+ comments. Users report that loading any page with a viral post takes 12 seconds. The post document for the most viral post is 14MB, approaching MongoDB 16MB document size limit, and some posts are now causing write failures. You need to redesign the data model without significant downtime. How do you approach this?

    **What weak candidates say:**
    "I'd just move comments to a separate collection and reference them by post ID."

    **What strong candidates say:**

    * This is a textbook example of embedded documents failing at scale. The fix is clear (move to a referenced model) but the migration strategy is the hard part. Covering both:
    * **Why the embedded model failed**: MongoDB loads the *entire document* into memory for any operation on it. A 14MB post document means reading 50,000 comments just to display the post title. Every new comment rewrites the entire document. At 16MB, writes hard-fail.
    * **Target data model**:

    ```javascript theme={null}
    // posts collection
    {
      _id: ObjectId,
      author: ObjectId,
      content: String,
      commentCount: Number,  // denormalized counter
      topComments: [/* top 3 comments embedded for preview */],
      createdAt: Date
    }

    // comments collection (separate)
    {
      _id: ObjectId,
      postId: ObjectId,     // indexed
      author: ObjectId,
      content: String,
      likes: Number,
      createdAt: Date       // indexed for pagination
    }
    ```

    * **The hybrid approach** is key: embed the top 3 comments (for the feed preview) and reference the rest. This gives you the read performance of embedding for the common case (showing a post with a few comments) while handling scale for viral posts.
    * **Migration strategy (zero-ish downtime)**:
      * **Phase 1**: Create the `comments` collection. Deploy new code that **writes to both** locations (embedded and referenced) using the dual-write pattern.
      * **Phase 2**: Run a background migration script that reads each post, extracts embedded comments, inserts them into the `comments` collection, and updates the post to keep only `topComments` + `commentCount`. Process in batches of 100 posts with a small delay between batches to avoid slamming the database.
      * **Phase 3**: Switch reads to the new `comments` collection. The feed still reads `topComments` from the post document.
      * **Phase 4**: Remove the old embedded comments array from post documents. Stop dual-writes.
    * **Index the comments collection**: `{postId: 1, createdAt: -1}` for paginated comment loading. Add `{postId: 1, likes: -1}` if you support "top comments" sorting.
    * **Pagination**: Use cursor-based pagination on `createdAt` rather than skip/limit. For a post with 50,000 comments, `skip(49000)` would scan and discard 49,000 documents:

    ```javascript theme={null}
    // Cursor-based: efficient at any offset
    db.comments.find({
      postId: postObjectId,
      createdAt: { $lt: lastSeenCommentDate }
    }).sort({ createdAt: -1 }).limit(20);
    ```

    * **Keeping `commentCount` in sync**: Use MongoDB change streams or handle it in the application layer. Accept that the count might be slightly stale. Facebook and Instagram do this too.

    **Follow-up:** A product manager asks if you should use MongoDB `$lookup` (aggregation join) to fetch post + comments in one query, or do two separate queries from the application layer. What are the performance trade-offs?

    **Follow-up:** You need to support threaded/nested comments (replies to replies). How does this change your data model? What is the trade-off between materialized path, adjacency list, and nested set models?

    **Follow-up:** How would you handle the case where a viral post gets 500 new comments per second? At what point does even the referenced model struggle, and what do you reach for next?
  </Accordion>

  <Accordion title="Scenario 9: Node.js Event Loop Starvation in an Express API">
    **Scenario:** Your Express API serves both REST endpoints and a real-time notification system via Server-Sent Events (SSE). Under load testing, you discover that when 500 SSE connections are active, the REST endpoints slow from 20ms to 3 seconds. The server CPU is only at 25%. Memory is fine. There are no database bottlenecks. What is happening and how do you fix it?

    **What weak candidates say:**
    "The server is probably overloaded. I'd add more instances or increase the thread pool."

    **What strong candidates say:**

    * Low CPU + high latency is the hallmark of **event loop starvation**. Something is blocking or monopolizing the event loop, preventing the REST handlers from executing. The CPU is low because most of the time is spent *waiting*, not *computing*. Here is the diagnosis:
    * **The SSE connection pattern is likely the culprit**. Each SSE connection is a long-lived HTTP response. If the notification system is doing any synchronous work per SSE tick like iterating over all 500 connections in a tight loop, serializing data, or checking conditions, that blocks the event loop for the duration.
    * **Common antipattern to look for**:

    ```javascript theme={null}
    // BAD: Synchronous broadcast to all SSE clients blocks the event loop
    function broadcastNotification(data) {
      const payload = JSON.stringify(data); // fine if small
      clients.forEach(client => {          // 500 iterations
        client.res.write(`data: ${payload}\n\n`);  // synchronous I/O write
      });
    }
    ```

    The `res.write()` call is not truly async. If the TCP write buffer is full (slow clients), it can block. With 500 connections, even small per-client overhead accumulates.

    * **Diagnosis with `--prof` and `clinic.js`**:
      * Run `clinic doctor -- node server.js` under load. It will show the event loop delay graph. Healthy is \<10ms. This likely shows 500ms+ delays.
      * Use `process.hrtime()` to measure event loop lag:

    ```javascript theme={null}
    setInterval(() => {
      const start = process.hrtime.bigint();
      setImmediate(() => {
        const delay = Number(process.hrtime.bigint() - start) / 1e6;
        if (delay > 50) logger.warn(`Event loop lag: ${delay}ms`);
      });
    }, 1000);
    ```

    * **Fix 1 - Batch SSE writes with `setImmediate`**:

    ```javascript theme={null}
    async function broadcastNotification(data) {
      const payload = `data: ${JSON.stringify(data)}\n\n`;
      const batch = 50;
      for (let i = 0; i < clients.length; i += batch) {
        const slice = clients.slice(i, i + batch);
        slice.forEach(c => c.res.write(payload));
        // Yield to event loop between batches
        await new Promise(resolve => setImmediate(resolve));
      }
    }
    ```

    * **Fix 2 - Separate SSE into its own process**: Use Node `cluster` module or a separate microservice for SSE connections. REST and SSE have fundamentally different resource profiles. REST is request-response (short bursts), SSE is long-lived (sustained connections). Mixing them on one event loop is asking for trouble.
    * **Fix 3 - Use Redis Pub/Sub for notification distribution**: Instead of one process managing all SSE connections, each Node process handles a subset. Notifications are published to a Redis channel, and each process subscribes and broadcasts to its own clients. This scales horizontally.
    * **The thread pool (`UV_THREADPOOL_SIZE`) is a red herring here.** That affects file I/O and DNS lookups, not HTTP connection handling. SSE operates on the main event loop.

    **Follow-up:** How does backpressure work in Node.js streams, and how would it affect your SSE implementation when a client has a slow connection?

    **Follow-up:** Would switching to WebSockets instead of SSE solve the event loop problem? What are the fundamental differences in how Node handles each?

    **Follow-up:** You decide to move SSE to a separate service. How do you handle the case where a user has an active SSE connection to Service A but their REST request that triggers a notification goes to Service B?
  </Accordion>

  <Accordion title="Scenario 10: Full-Stack Performance Audit Under Business Pressure">
    **Scenario:** Your MERN e-commerce app has a Lighthouse score of 34 on mobile. The CEO just read an article that every 100ms of latency costs 1% in revenue. Google Core Web Vitals are failing: LCP is 8.2s (target \<2.5s), FID is 380ms (target \<100ms), CLS is 0.45 (target \<0.1). The backend API p95 is 800ms. You have 2 weeks and one other developer to make meaningful improvements. What is your prioritized action plan?

    **What weak candidates say:**
    "I'd optimize images, add lazy loading, and enable caching. Maybe switch to Next.js for SSR."

    **What strong candidates say:**

    * Two weeks with two developers means ruthless prioritization. The key is to identify the highest-impact, lowest-effort fixes first. Here is the plan, ordered by expected impact:
    * **Week 1 — The 80/20 Fixes** (target: Lighthouse 60+, LCP \<4s):
      * **Fix LCP (8.2s to target \<4s)**: LCP is usually the hero image or the largest text block. Run Lighthouse and check what element is the LCP.
        * If it is an image: Convert to WebP/AVIF, add `width`/`height` attributes to prevent layout shift, add `fetchpriority="high"` and `loading="eager"` to the LCP image specifically, serve via CDN (CloudFront/Cloudflare). This alone can cut 3-4 seconds.
        * If it is text rendered after a large JS bundle: That is a code-splitting problem. The main bundle is probably 2MB+ uncompressed. Implement route-based code splitting with `React.lazy()` and `Suspense`.
        * Check if the font is render-blocking. Add `font-display: swap` to `@font-face` declarations. Preload the primary font with a link preload tag with `as="font"` and `crossorigin`.
      * **Fix CLS (0.45 to target \<0.1)**: This is almost always caused by images without dimensions, dynamically injected ads/banners, or web fonts causing FOUT (Flash of Unstyled Text).
        * Add explicit `width` and `height` to every `img` tag.
        * Reserve space for dynamic content with CSS `min-height` or `aspect-ratio`.
        * Audit for any content that loads after initial paint and pushes things around.
      * **Fix the 800ms API p95**: Run `explain()` on the top 5 slowest MongoDB queries (get these from Atlas Slow Query Analyzer or Mongoose debug mode). Add missing indexes. Enable `compression` middleware on Express. Add Redis caching for the product listing and category pages since they are read-heavy and cache-friendly.
    * **Week 2 — Deeper Optimizations** (target: Lighthouse 70+, LCP \<3s):
      * **Fix FID (380ms to target \<100ms)**: High FID means the main thread is blocked during page load. The culprit is JavaScript, too much of it executing synchronously.
        * Audit the bundle with `vite-plugin-visualizer` or `source-map-explorer`. Find the largest dependencies. Common offenders: `moment.js` (replace with `date-fns` or `dayjs`), full `lodash` import (switch to `lodash-es` with tree-shaking), analytics libraries loading synchronously.
        * Defer non-critical third-party scripts: analytics, chat widgets, social embeds. Use `async` or `defer` attributes on script tags, or load them after `window.onload`.
        * Move heavy computations to web workers if applicable.
      * **Enable HTTP/2 on Nginx**: Multiplexed connections eliminate head-of-line blocking. This is a config change, not code.
      * **Add `stale-while-revalidate` caching headers** for API responses that tolerate slight staleness (product listings, categories):

    ```javascript theme={null}
    res.set('Cache-Control', 'public, max-age=60, stale-while-revalidate=300');
    ```

    * **Implement incremental static regeneration** (if using Next.js) or pre-render critical pages to HTML at build time.
    * **What NOT to do in 2 weeks**: Migrate to Next.js (too risky for a rewrite under pressure), implement a CDN from scratch (use Cloudflare with 5-minute setup), or "optimize all images" (focus only on above-the-fold and LCP images first).
    * **Measurement cadence**: Run Lighthouse CI on every PR. Set up Real User Monitoring (RUM) with web-vitals library to track field data, not just lab data. Report daily to the CEO with the specific numbers and the revenue impact estimate.

    **Follow-up:** The CEO asks why you are not just "switching to Next.js for SSR" since that would fix everything. How do you explain the trade-offs and risks of that migration under time pressure?

    **Follow-up:** After your fixes, Lighthouse shows 72 but real users on 3G connections in India still report 6-second load times. What is the gap between lab data and field data, and how do you optimize for real-world conditions?

    **Follow-up:** How would you set up a performance budget that prevents the team from regressing these metrics as new features are added?
  </Accordion>
</AccordionGroup>

<hr />

## Conclusion and Interview Tips

This comprehensive guide covers essential MERN Stack interview questions across all four technologies. The MERN stack combines MongoDB, Express.js, React, and Node.js to create powerful full-stack web applications.

### Key Interview Preparation Tips

* **Master fundamentals before advanced topics** -- interviewers can tell immediately if you memorized answers vs truly understand concepts. Start with the event loop, reconciliation, and middleware pipeline before touching optimization techniques
* **Build a full-stack project and deploy it** -- nothing replaces the experience of debugging a production CORS issue at 2am or figuring out why your MongoDB queries are slow with real data
* **Understand how technologies integrate** -- the best MERN candidates can trace a request from React click to MongoDB write and back. Most candidates only know one layer deeply
* **Focus on trade-offs, not just solutions** -- senior interviewers care more about *why* you chose X over Y than whether you know X exists
* **Know your tools and metrics** -- be able to name specific tools: React DevTools Profiler for render performance, `explain()` for MongoDB queries, Lighthouse for Core Web Vitals, Sentry for error tracking

### During the Interview

* **Ask clarifying questions before coding** -- "What scale are we talking about? How many concurrent users? What are the consistency requirements?" shows senior thinking
* **Think aloud to show your problem-solving approach** -- interviewers cannot evaluate what they cannot hear. Verbalize trade-offs as you consider them
* **Lead with the "why" before the "how"** -- "I would use Redis here because we need sub-millisecond lookups and the data has a natural TTL" is much stronger than "I would use Redis"
* **Discuss trade-offs in your solutions** -- every technical decision has downsides. Acknowledging them shows engineering maturity
* **Be honest about edges of your knowledge** -- "I have not used that in production, but my understanding is..." is far better than confidently giving a wrong answer

### What Separates Good from Great Candidates

| Good Candidate                            | Great Candidate                                                                      |
| ----------------------------------------- | ------------------------------------------------------------------------------------ |
| Knows what React.memo does                | Knows when React.memo hurts performance                                              |
| Can write a JWT auth flow                 | Can explain why JWTs in localStorage are insecure                                    |
| Understands MongoDB indexing              | Can design the right compound index for a given query pattern                        |
| Knows the event loop phases               | Can explain why `setImmediate` and `process.nextTick` have different use cases       |
| Lists performance optimization techniques | Measures first, optimizes second, and can explain the specific bottleneck they fixed |

<Info>
  Remember that interviews assess not just technical knowledge but also problem-solving ability, communication skills, and engineering judgment. The best candidates do not just know the answers -- they understand the reasoning behind them and can adapt their knowledge to novel situations.
</Info>
