# What is Middleware in Express and How It Works

Middleware is one of the most important concepts in building scalable, flexible web applications and APIs with Express.js. Middleware is a way to tap into the request/response cycle and do some logic before the requests hit your main route handlers or before responses are sent back to clients.

Think of middleware like checkpoints or stations on an assembly line. Every incoming request passes through one or more middleware functions before returning a response.

Let’s see what middleware is, where it fits into Express and see practical examples for common use cases.

### **What Is Middleware in Express?**

In Express, middleware is just a function that gets the request and response objects (like a route handler), but it can do three main things:

1.  Modify or post the request before it gets to the route handler.
    
2.  Before returning a response to the client, read or edit it.
    
3.  Decide if request should continue, hand control to next middleware, or end request/response cycle.
    

**Basic Middleware Signature:**

```javascript
function myMiddleware(req, res, next) {
  // ...logic here
  next(); // Pass control to the next middleware or route
}
```

Notice the third argument: `next`. This is a special function provided by Express to move the request along the pipeline.

### **Where Middleware Sits in the Request Lifecycle**

When a request hits your Express app:

1.  The request enters Express.
    
2.  It passes through any configured middleware functions in order.
    
3.  Eventually it reaches a route handler (if not ended early by middleware).
    
4.  The response is sent and the cycle ends.
    

**Analogy:**  
Imagine a package traveling through an assembly line.  
Each station (middleware) can check it, add a sticker, reject it, wrap it, or send it to the next station.  
Finally, the package is delivered (response sent back).

### **Types of Middleware in Express**

Express supports several types of middleware, each suited for different use cases.

## **1\. Application-Level Middleware**

These are functions applied to the whole app.

**Example: Logging Middleware**

```javascript
const express = require("express");
const app = express();

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

*   `app.use()` applies the middleware to every request.
    
*   You must call `next()` to let the pipeline continue!
    

## **2\. Router-Level Middleware**

Middleware attached to specific routers or sets of routes.

**Example: Protect Admin Routes**

```javascript
const express = require("express");
const adminRouter = express.Router();

adminRouter.use((req, res, next) => {
  if (!req.user || !req.user.isAdmin) {
    return res.status(403).send("Forbidden");
  }
  next();
});

adminRouter.get("/dashboard", (req, res) => {
  res.send("Admin Dashboard");
});
```

You attach the router to the app (`app.use("/admin", adminRouter);`) and only `/admin` routes will use that middleware.

## **3\. Built-In Middleware**

Express provides built-in middleware for common needs:

*   `express.json()` – Automatically parses incoming JSON requests.
    
*   `express.urlencoded()` – Parses URL-encoded form data.
    
*   `express.static()` – Serves static files like images or CSS.
    

**Example:**

```javascript
app.use(express.json());
```

Now every incoming JSON body is parsed and accessible as `req.body`.

### **Execution Order of Middleware in Express**

**Order matters!**  
Express runs middleware in the order you define it.

```javascript
app.use(middlewareA);
app.use(middlewareB);

app.get("/hello", routeHandler);
```

*   A request goes to `middlewareA` first, then `middlewareB`, then `routeHandler`.
    
*   If any middleware does **not** call `next()`, the request halts immediately and never reaches the route.
    

**Middleware can:**

*   Continue to the next function (`next()`)
    
*   End the response (`res.send()`)
    
*   Pass errors to the next error handler (`next(err)`)  
    

### **Role of the next() Function**

*   `next()` is how you tell Express to “move on” to the next thing in the pipeline.
    
*   Without `next()`, the request will hang forever (unless you send a response).
    
*   You can call `next(err)` to signal an error and invoke error-handling middleware.
    

### **Middleware Execution Sequence: A Visual Example**

  
Consider:

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

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

app.get("/", (req, res) => {
  res.send("Done!");
});
```

Request to `/` will print:

```plaintext
First middleware
Second middleware
```

And then respond with `Done!`.

If you send a response inside middleware (e.g., `res.send("403 Forbidden")`), Express skips all the remaining middleware and routes.

# **Real-World Examples of Middleware**

  
**1\. Logging All Requests**

```javascript
app.use((req, res, next) => {
  console.log(`\({req.method} \){req.url} at ${new Date()}`);
  next();
});
```

## **2\. Authentication “Checkpoint”**

```javascript
function authenticate(req, res, next) {
  if (!req.user) {
    return res.status(401).send("Unauthorized");
  }
  next();
}
app.use("/dashboard", authenticate);
```

## **3\. Request Validation**

```javascript
function validateUserInput(req, res, next) {
  if (!req.body.username || !req.body.password) {
    return res.status(400).json({ error: "Missing fields" });
  }
  next();
}
app.post("/signup", validateUserInput, (req, res) => {
  // Create user
});
```

*   If validation fails, middleware ends the cycle with a `400` response.
    
*   If it passes, the actual signup route runs.  
      
    

### **Request Pipeline Analogy**

Imagine each call as passing through a pipeline of functions:

*   Middleware 1: Add user info if logged in
    
*   Middleware 2: Validating input.
    
*   Middleware 3: Log the request
    
*   Route Handler: Handle the request and send the response.
    

Each middleware can inspect, modify or even stop the request before it finally reaches the actual route handler.

### **Best Practices & Notes**

*   Put global middleware (e.g logging, json parsing) as soon as possible.
    
*   Use router-level middleware for features that are only needed on some route groups (like admin auth)
    
*   Always call ​ unless you send a response or encounter an error.
    
*   The order of middleware is important . Earlier middleware can influence later middleware and route handlers .
    
*   Middleware can also return errors / responses, which stops the pipeline.line.
    

  
**Conclusion**

In Express, middleware is a chain of functions that execute during the lifecycle of a request to the server. It enables you to:

*   Add features and behaviour to your app without changing route handlers
    
*   Reuse common processing logic (authentication, logging, input validation, etc.)
    
*   Manage the flow of requests and responses
    

Understanding middleware can give you a very powerful way to control every request in your Express application. It makes your code modular, testable and maintainable.
