Skip to content
Bill Liao
Go back

100 Express.js interview Questions and Answers

Edit page

Below is an interview-focused guide covering Express.js fundamentals, middleware, routing, REST APIs, security, performance, testing, architecture, and production best practices.


1. Express.js Fundamentals

1. What is Express.js?

Answer:
Express.js is a lightweight, fast web application framework for Node.js. It provides features for:

Express intentionally provides a relatively minimal abstraction over Node.js’s HTTP capabilities.


Answer:

Its popularity comes from:

Example:

const express = require("express");

const app = express();

app.get("/hello", (req, res) => {
  res.json({ message: "Hello World" });
});

app.listen(3000);

3. What is the difference between Node.js and Express.js?

Answer:

Node.jsExpress.js
JavaScript runtimeWeb framework
Provides HTTP moduleBuilt on Node.js
Lower-level APIsHigher-level abstractions
Requires more boilerplateSimplifies web development
Provides event loopProvides routing/middleware

Express runs on top of Node.js.


4. How do you install Express?

Answer:

Bash

npm install express

Then:

JavaScript

const express = require("express");

With ES modules:

JavaScript

import express from "express";

5. How do you create a basic Express application?

Answer:

import express from "express";

const app = express();

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

app.listen(3000);

6. What does express() return?

Answer:

express() creates and returns an Express application instance.

JavaScript

const app = express();

The app object provides methods such as:

app.get()
app.post()
app.put()
app.delete()
app.use()
app.listen()

7. What is app.listen()?

Answer:

app.listen() starts an HTTP server that listens for incoming requests.

app.listen(3000, () => {
  console.log("Server started");
});

Conceptually, Express configures a Node.js HTTP server around the application.


8. What is middleware in Express?

Answer:

Middleware is a function that executes during the request-response lifecycle.

A middleware function typically has:

JavaScript

(req, res, next)

Example:

app.use((req, res, next) => {
  console.log(req.method, req.url);
  next();
});

Middleware can:


9. What does next() do?

Answer:

next() passes control to the next middleware or route handler.

app.use((req, res, next) => {
  console.log("Middleware");
  next();
});

If middleware does not call next() and does not send a response, the request can remain hanging.


10. What happens if you don’t call next()?

Answer:

If middleware doesn’t:

the request may never complete.

Example of problematic middleware:

app.use((req, res, next) => {
  console.log("Request received");
});

The request will typically hang.


2. Middleware

11. What are the different types of Express middleware?

Answer:

Common categories include:

  1. Application-level middleware
  2. Router-level middleware
  3. Built-in middleware
  4. Third-party middleware
  5. Error-handling middleware

12. What is application-level middleware?

Answer:

Middleware attached directly to the Express application.

app.use((req, res, next) => {
  console.log("Application middleware");
  next();
});

It can apply to all routes or a specific path.

JavaScript

app.use("/api", middleware);

13. What is router-level middleware?

Answer:

Router-level middleware is attached to an express.Router() instance.

const router = express.Router();

router.use(authMiddleware);

router.get("/users", getUsers);

app.use("/api", router);

This is useful for modular applications.


14. What is built-in middleware?

Answer:

Express provides several built-in middleware functions.

Common examples:

express.json()
express.urlencoded()
express.static()

Example:

JavaScript

app.use(express.json());

15. What does express.json() do?

Answer:

It parses incoming requests containing JSON payloads.

For example:

POST /users
Content-Type: application/json

{
  "name": "John"
}

Then:

app.post("/users", (req, res) => {
  console.log(req.body.name);
});

Without appropriate body-parsing middleware, req.body may be undefined.


16. What does express.urlencoded() do?

Answer:

It parses URL-encoded request bodies.

JavaScript

app.use(express.urlencoded({ extended: true }));

It is commonly used with HTML form submissions.


17. What is express.static()?

Answer:

It serves static files such as:

Example:

JavaScript

app.use(express.static("public"));

A file:

public/logo.png

can then be served through the application.


18. What is third-party middleware?

Answer:

Middleware provided by external packages.

Examples include:

Example:

import cors from "cors";

app.use(cors());

19. What is middleware execution order?

Answer:

Express executes middleware in the order in which it is registered.

app.use(first);
app.use(second);
app.get("/", handler);

Execution:

first
 ↓
second
 ↓
handler

Therefore, middleware ordering is extremely important.


20. Why is middleware ordering important?

Answer:

Because later middleware cannot generally affect earlier processing.

For example:

app.use(express.json());

app.post("/users", handler);

The JSON parser must execute before the route handler if the handler needs req.body.


21. How do you create authentication middleware?

Answer:

function authenticate(req, res, next) {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({
      message: "Unauthorized"
    });
  }

  next();
}

Then:

app.get("/profile", authenticate, (req, res) => {
  res.json({ message: "Profile" });
});

22. Can middleware modify req?

Answer:

Yes.

For example:

req.user = user;
next();

Later middleware or route handlers can access:

JavaScript

req.user

This is commonly used after authentication.


23. Can middleware modify res?

Answer:

Yes.

Middleware can add properties or headers.

res.setHeader("X-App-Version", "1.0");
next();

However, application-specific data is usually better kept in controlled request context rather than arbitrarily modifying the response object.


24. What is middleware composition?

Answer:

Middleware composition means combining multiple middleware functions.

app.get(
  "/admin",
  authenticate,
  authorize,
  validateRequest,
  controller
);

The request flows through each function in order.


25. What is a middleware factory?

Answer:

A middleware factory is a function that creates middleware based on configuration.

function authorize(role) {
  return (req, res, next) => {
    if (req.user.role !== role) {
      return res.sendStatus(403);
    }

    next();
  };
}

Usage:

app.get(
  "/admin",
  authorize("admin"),
  handler
);

3. Routing

26. What is routing in Express?

Answer:

Routing determines how an application responds to a particular HTTP method and URL.

Example:

app.get("/users", getUsers);
app.post("/users", createUser);
app.get("/users/:id", getUser);

27. What HTTP methods does Express support?

Answer:

Common methods include:

GET
POST
PUT
PATCH
DELETE
OPTIONS
HEAD

Express also supports route patterns and app.all().


28. What is the difference between PUT and PATCH?

Answer:

PUT is generally used for replacing a resource.

http

PUT /users/123

PATCH is generally used for partial updates.

http

PATCH /users/123

For example:

{
  "email": "new@example.com"
}

only changes the email.


29. What are route parameters?

Answer:

Route parameters are dynamic values embedded in the URL.

app.get("/users/:id", (req, res) => {
  console.log(req.params.id);
});

Request:

/users/123

produces:

JavaScript

req.params.id === "123"

30. What are query parameters?

Answer:

Query parameters appear after ?.

Example:

/users?page=2&limit=20

Access them using:

req.query.page
req.query.limit

31. What is the difference between req.params and req.query?

Answer:

req.params contains route parameters:

/users/123

JavaScript

req.params.id

req.query contains query-string parameters:

/users?page=2

JavaScript

req.query.page

32. What is req.body?

Answer:

req.body contains data sent in the request body.

Example:

{
  "name": "Alice"
}

Access:

JavaScript

req.body.name

The appropriate body-parsing middleware must be enabled.


33. What is express.Router()?

Answer:

express.Router() creates a modular route handler.

const router = express.Router();

router.get("/", getUsers);
router.post("/", createUser);

export default router;

Then:

JavaScript

app.use("/users", router);

34. Why use Express Router?

Answer:

It helps separate routes by feature.

For example:

routes/
  users.js
  orders.js
  products.js

This improves:


35. What is route chaining?

Answer:

You can define multiple HTTP methods for the same path.

app.route("/users")
  .get(getUsers)
  .post(createUser);

36. What is app.use() used for?

Answer:

app.use() is primarily used to register middleware and routers.

app.use(express.json());

app.use("/api/users", userRouter);

37. What is the difference between app.use() and app.get()?

Answer:

app.use() is primarily for middleware and mounting routers.

JavaScript

app.use("/api", router);

app.get() handles GET requests for a route.

JavaScript

app.get("/users", handler);

38. What is a wildcard route?

Answer:

A wildcard route catches requests matching a broad pattern.

For example, applications may use a final fallback handler for unmatched routes.

app.use((req, res) => {
  res.status(404).json({
    message: "Not Found"
  });
});

This is often preferable to relying on a broad route pattern.


39. How do you handle 404 errors?

Answer:

Place a final middleware after all routes:

app.use((req, res) => {
  res.status(404).json({
    message: "Route not found"
  });
});

40. What is route parameter validation?

Answer:

It verifies that parameters meet expected constraints.

For example:

app.get("/users/:id", (req, res) => {
  const id = Number(req.params.id);

  if (!Number.isInteger(id)) {
    return res.status(400).json({
      message: "Invalid user ID"
    });
  }

  // ...
});

In production, dedicated validation libraries can provide more robust schemas.


4. Request and Response

41. What are req and res?

Answer:

req represents the incoming HTTP request.

res represents the HTTP response.

app.get("/", (req, res) => {
  res.json({
    method: req.method,
    url: req.url
  });
});

42. What does res.send() do?

Answer:

It sends a response to the client.

JavaScript

res.send("Hello");

Express determines an appropriate content type based on the value.


43. What does res.json() do?

Answer:

It sends a JSON response.

res.json({
  id: 1,
  name: "Alice"
});

This is commonly used in REST APIs.


44. What does res.status() do?

Answer:

It sets the HTTP status code.

res.status(201).json({
  message: "Created"
});

45. What does res.end() do?

Answer:

res.end() terminates the response.

JavaScript

res.status(204).end();

It is generally used when no response body is required.


46. What is method chaining in Express responses?

Answer:

Express allows response methods to be chained:

res
  .status(201)
  .json({
    message: "Created"
  });

47. How do you set response headers?

Answer:

Use:

JavaScript

res.set("X-Custom-Header", "value");

or:

JavaScript

res.setHeader("X-Custom-Header", "value");

48. How do you redirect in Express?

Answer:

Use:

JavaScript

res.redirect("/login");

You can also specify a status:

JavaScript

res.redirect(301, "/new-location");

49. How do you send a file?

Answer:

Use:

JavaScript

res.sendFile("/path/to/file.pdf");

The path should be constructed safely and intentionally.


50. What is res.locals?

Answer:

res.locals stores request-scoped values that are available to later middleware and route handlers.

res.locals.user = user;
next();

It is particularly useful with server-side rendering.


5. REST API Development

51. How do you create a REST API with Express?

Answer:

Example:

app.get("/users", getUsers);
app.get("/users/:id", getUser);
app.post("/users", createUser);
app.put("/users/:id", updateUser);
app.delete("/users/:id", deleteUser);

52. What HTTP status code should be returned after creating a resource?

Answer:

Typically:

201 Created

Example:

JavaScript

res.status(201).json(user);

53. What status code should be returned for invalid input?

Answer:

Usually:

400 Bad Request

For example:

res.status(400).json({
  message: "Invalid request"
});

Some API designs use 422 Unprocessable Content for semantically invalid input.


54. What status code should be returned when authentication is missing?

Answer:

Typically:

401 Unauthorized

Example:

JavaScript

res.sendStatus(401);

55. What status code should be returned when the user lacks permission?

Answer:

Typically:

403 Forbidden

The distinction is:

401 → authentication required/failed
403 → authenticated but not permitted

56. What status code should be returned when a resource doesn’t exist?

Answer:

Usually:

404 Not Found

Example:

res.status(404).json({
  message: "User not found"
});

57. How should API errors be structured?

Answer:

A consistent error format is important.

For example:

{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "User does not exist",
    "requestId": "abc123"
  }
}

Consistency makes APIs easier to consume and monitor.


58. What is API versioning?

Answer:

API versioning allows an API to evolve without unexpectedly breaking existing clients.

Common approach:

/api/v1/users
/api/v2/users

Example:

JavaScript

app.use("/api/v1", v1Router);

59. How do you implement pagination?

Answer:

A basic approach uses query parameters:

/users?page=2&limit=20

Then:

const page = Number(req.query.page || 1);
const limit = Number(req.query.limit || 20);

Production APIs should also enforce maximum limits.


60. What is cursor-based pagination?

Answer:

Instead of using page numbers, the client receives a cursor representing a position in the dataset.

Example:

/users?limit=20&cursor=abc123

Cursor pagination is often more reliable for large, frequently changing datasets.


6. Error Handling

61. How does Express handle errors?

Answer:

Express supports special error-handling middleware:

JavaScript

(err, req, res, next)

Example:

app.use((err, req, res, next) => {
  res.status(500).json({
    message: "Internal Server Error"
  });
});

62. Where should error middleware be placed?

Answer:

Usually at the end of the middleware and route chain:

app.use(routes);

app.use(notFoundHandler);

app.use(errorHandler);

63. What is the signature of error-handling middleware?

Answer:

It has four parameters:

JavaScript

(err, req, res, next)

Example:

function errorHandler(err, req, res, next) {
  // handle error
}

The four-argument signature tells Express that this is error-handling middleware.


64. How do you handle asynchronous errors?

Answer:

A robust modern pattern is to propagate rejected promises to the error handler, either using Express’s built-in async error propagation where supported or a small wrapper for older patterns.

Example:

app.get("/users", async (req, res, next) => {
  try {
    const users = await getUsers();

    res.json(users);
  } catch (error) {
    next(error);
  }
});

65. Why should you call next(err)?

Answer:

It passes the error to Express’s error-handling middleware.

try {
  // operation
} catch (err) {
  next(err);
}

This centralizes error handling.


66. What is a custom error class?

Answer:

A custom error class represents application-specific errors.

class NotFoundError extends Error {
  constructor(message) {
    super(message);
    this.statusCode = 404;
  }
}

Then:

JavaScript

throw new NotFoundError("User not found");

67. Why centralize error handling?

Answer:

Centralized handling provides:


68. Should production APIs expose stack traces?

Answer:

Generally, no.

Stack traces can reveal:

Instead, log detailed errors internally and return safe error messages to clients.


69. How do you distinguish operational and programming errors?

Answer:

Operational errors are expected runtime failures, such as:

Programming errors include bugs such as:

Operational errors can often be handled gracefully; programming errors generally require fixing the code.


70. What happens when an error occurs after headers are sent?

Answer:

You should avoid trying to send another response.

A common pattern is:

if (res.headersSent) {
  return next(err);
}

This allows Express/the underlying server to handle the situation appropriately.


7. Authentication and Security

71. How do you secure an Express application?

Answer:

Important measures include:


72. What is Helmet?

Answer:

Helmet is middleware that helps set security-related HTTP headers.

Example:

import helmet from "helmet";

app.use(helmet());

It helps mitigate several classes of browser-based attacks.


73. What is CORS?

Answer:

CORS stands for Cross-Origin Resource Sharing.

It controls which browser origins can access resources from another origin.

Example:

import cors from "cors";

app.use(cors({
  origin: "https://example.com"
}));

74. Why shouldn’t you use cors() blindly?

Answer:

This:

JavaScript

app.use(cors());

may allow broader cross-origin access than intended.

For production systems, configure allowed origins explicitly when possible.


75. What is JWT authentication?

Answer:

JWT stands for JSON Web Token.

A client authenticates and receives a token:

Authorization: Bearer <token>

Middleware validates the token before allowing access to protected resources.


76. Where should JWTs be stored?

Answer:

It depends on the application architecture.

For browser applications, storing sensitive tokens in JavaScript-accessible storage can increase exposure to XSS. Secure, appropriately configured cookies are often preferable for session-like authentication.

Important cookie attributes include:

HttpOnly
Secure
SameSite

77. What is session-based authentication?

Answer:

The server maintains session state.

The client typically receives a session identifier in a cookie:

Cookie: sessionId=abc123

The server maps that identifier to the user’s session.


78. JWT vs session authentication?

Answer:

JWTSession
Token contains claimsServer stores session state
Can be statelessUsually stateful
Revocation can be harderRevocation is straightforward
Useful across servicesSimple for many web apps
Token size can be largerCookie usually contains an ID

Neither is universally superior.


79. How do you prevent brute-force attacks?

Answer:

Use:

Example:

JavaScript

app.use("/login", rateLimiter);

80. How do you prevent request payload attacks?

Answer:

Limit request sizes:

app.use(express.json({
  limit: "1mb"
}));

Also validate:


8. Database and Architecture

81. Should database logic be placed directly inside routes?

Answer:

For small applications it can be acceptable, but large applications benefit from separation.

A common architecture is:

Route
  ↓
Controller
  ↓
Service
  ↓
Repository
  ↓
Database

This improves testability and maintainability.


82. What is the controller layer?

Answer:

Controllers handle HTTP-specific concerns.

For example:

async function getUser(req, res, next) {
  try {
    const user = await userService.getUser(req.params.id);

    res.json(user);
  } catch (error) {
    next(error);
  }
}

83. What is the service layer?

Answer:

The service layer contains business logic.

async function createUser(data) {
  // business rules
  // validation
  // persistence orchestration
}

It should not depend heavily on Express-specific objects.


84. What is the repository pattern?

Answer:

The repository abstracts data access.

const userRepository = {
  findById(id) {
    // database query
  }
};

This separates database concerns from business logic.


85. How do you connect Express to MongoDB?

Answer:

A popular approach is using the MongoDB Node.js driver or Mongoose.

Example conceptually:

JavaScript

await mongoose.connect(process.env.MONGODB_URI);

The application should establish database connectivity during startup and handle connection failures appropriately.


86. How do you connect Express to PostgreSQL?

Answer:

You can use libraries such as pg.

Conceptually:

const pool = new Pool({
  connectionString: process.env.DATABASE_URL
});

Then:

const result = await pool.query(
  "SELECT * FROM users WHERE id = $1",
  [id]
);

Parameterized queries help prevent SQL injection.


87. How do you prevent SQL injection?

Answer:

Use parameterized queries or a properly designed ORM/query builder.

Bad:

JavaScript

const sql = `SELECT * FROM users WHERE id = ${id}`;

Better:

await pool.query(
  "SELECT * FROM users WHERE id = $1",
  [id]
);

88. How should database connections be managed?

Answer:

Use connection pooling rather than opening a new database connection for every request.

A pool:


89. How should transactions be handled?

Answer:

Transactions should normally be managed at the service/data-access boundary rather than inside Express route definitions.

For example:

Controller
   ↓
Service
   ↓
Transaction
   ├── Update A
   ├── Update B
   └── Commit

If something fails:

Rollback

90. How do you manage environment variables?

Answer:

Use environment variables for configuration and secrets.

Example:

JavaScript

const port = process.env.PORT || 3000;

Typical values include:

DATABASE_URL
JWT_SECRET
API_KEY
PORT

Never hard-code production secrets into source code.


9. Performance and Production

91. How do you improve Express performance?

Answer:

Common techniques include:


92. Why should you avoid synchronous APIs?

Answer:

Node.js uses an event-driven architecture. Long synchronous operations can block the event loop.

Avoid unnecessary operations such as:

JavaScript

fs.readFileSync(...)

in request paths.

Prefer asynchronous APIs:

JavaScript

await fs.promises.readFile(...)

93. What is compression middleware?

Answer:

Compression reduces response size.

Example:

import compression from "compression";

app.use(compression());

It can reduce bandwidth usage but also introduces CPU overhead, so production configuration should consider traffic patterns and infrastructure.


94. How do you scale an Express application?

Answer:

A common strategy is horizontal scaling:

              Load Balancer
              /     |     \
          Server  Server  Server

Because HTTP application instances can often be stateless, multiple instances can handle requests.

Shared state should typically be moved to external systems such as:


95. How do you use Express behind a reverse proxy?

Answer:

A production architecture might look like:

Internet
   ↓
CDN / Load Balancer
   ↓
Reverse Proxy
   ↓
Express
   ↓
Database / Services

Examples of reverse proxies include Nginx and cloud load balancers.


96. What is trust proxy?

Answer:

trust proxy tells Express which proxy layers should be trusted.

Example:

JavaScript

app.set("trust proxy", 1);

This affects values such as:

req.ip
req.protocol
req.hostname

It should be configured according to the actual deployment topology rather than enabled indiscriminately.


97. How do you implement graceful shutdown?

Answer:

Listen for termination signals and stop accepting new traffic while allowing existing requests to finish.

Conceptually:

const server = app.listen(PORT);

process.on("SIGTERM", () => {
  server.close(() => {
    console.log("Server closed");
    process.exit(0);
  });
});

Production applications should also close database pools, message consumers, and other resources.


98. How do you monitor an Express application?

Answer:

Monitor:

Common observability components include:

Logs
Metrics
Traces
Alerts

A request ID or correlation ID is also extremely useful for distributed systems.


10. Testing and Advanced Questions

99. How do you test an Express API?

Answer:

A common stack is:

Jest/Vitest
+
Supertest

Example:

import request from "supertest";

test("GET /users", async () => {
  const response = await request(app)
    .get("/users");

  expect(response.status).toBe(200);
});

For better testability, export the Express application separately from the process that calls listen().

For example:

// app.js
export default app;

and:

// server.js
app.listen(PORT);

100. How would you design a production-ready Express.js application?

Answer:

A strong production architecture might look like:

                    ┌──────────────────┐
                    │      Client      │
                    └────────┬─────────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │ CDN / Load       │
                    │ Balancer / Proxy  │
                    └────────┬─────────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │    Express API   │
                    └────────┬─────────┘
                             │
              ┌──────────────┼──────────────┐
              ▼              ▼              ▼
        ┌──────────┐   ┌──────────┐   ┌──────────┐
        │Middleware│   │ Services │   │Validation│
        └──────────┘   └────┬─────┘   └──────────┘
                            │
                    ┌───────┴────────┐
                    ▼                ▼
              ┌──────────┐     ┌──────────┐
              │ Database │     │  Redis   │
              └──────────┘     └──────────┘
                    │
                    ▼
              ┌──────────────┐
              │ External APIs│
              └──────────────┘

A production-ready Express application should include:

Architecture

Security

Reliability

Performance

Observability

Testing


🔥 10 Express.js Questions Interviewers Often Use to Go Deeper

If you’re interviewing for a Senior/Lead Full-Stack or Backend Engineer role, don’t stop at the 100 questions above. Interviewers often use these follow-ups to distinguish junior developers from senior engineers:

  1. How does Express middleware actually work internally?
  2. What happens when an async Express handler throws an error?
  3. How would you prevent blocking the Node.js event loop?
  4. How would you design an Express API for 10,000+ requests per second?
  5. How would you implement distributed rate limiting?
  6. How would you design authentication for multiple microservices?
  7. How would you handle idempotency for POST requests?
  8. How would you implement request tracing across Express → Kafka → downstream services?
  9. How would you gracefully shut down an Express service running in Kubernetes?
  10. How would you structure a large Express.js monorepo with 100+ APIs?

⭐ One particularly important senior-level concept

A strong answer to many Express interviews is:

Express is not the architecture. Express is the HTTP delivery mechanism.

For a large production system, you want something closer to:

HTTP / Express
      ↓
Middleware
      ↓
Controller
      ↓
Application Service
      ↓
Domain Logic
      ↓
Repository / Gateway
      ↓
Database / Kafka / External APIs

This distinction is important because Express should handle HTTP concerns, while business logic should remain independent of the web framework.

That architecture makes the application easier to:


For a senior Java/Node.js full-stack interview, I’d prioritize these areas:

PriorityTopicImportance
🔴 1Middleware⭐⭐⭐⭐⭐
🔴 2Async/Error Handling⭐⭐⭐⭐⭐
🔴 3REST API Design⭐⭐⭐⭐⭐
🔴 4Authentication & Security⭐⭐⭐⭐⭐
🔴 5Node.js Event Loop⭐⭐⭐⭐⭐
🔴 6Performance & Scaling⭐⭐⭐⭐⭐
🟠 7Express Router⭐⭐⭐⭐
🟠 8Database Integration⭐⭐⭐⭐
🟠 9Testing⭐⭐⭐⭐
🟠 10Production Architecture⭐⭐⭐⭐⭐
🟡 11Caching/Redis⭐⭐⭐
🟡 12Kafka/Event-Driven Architecture⭐⭐⭐⭐
🟡 13Kubernetes Deployment⭐⭐⭐⭐
🟡 14Observability⭐⭐⭐⭐
🟡 15System Design⭐⭐⭐⭐⭐

The biggest mistake in Express interviews is memorizing app.get(), app.use(), and req/res APIs without understanding Node.js underneath them. For senior roles, expect the interviewer to move quickly from Express into event-loop behavior, asynchronous error handling, API security, distributed systems, scalability, observability, and system design.


Edit page
Share this post:

Next Post
100 Node.js interview Questions and Answers