Skip to main content
Node.js Basics
CHAPTER 15 Beginner

Express.js Middleware

Updated: May 13, 2026
25 min read

# Express.js Middleware

Welcome to Chapter 15! If you want to truly master Express.js, you must understand Middleware. It is the most important concept in the framework.

Imagine a bouncer at a nightclub. Before you can get to the dance floor (the route), the bouncer (the middleware) checks your ID. If you're old enough, he lets you in. If not, he rejects you. Middleware functions are just like that bouncer—they stand between the incoming request and the final route response.

---

1. Introduction

Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application's request-response cycle.

Middleware can:

  1. 1. Execute any code.
  1. 2. Make changes to the request and the response objects.
  1. 3. End the request-response cycle (e.g., send an error).
  1. 4. Call the next() middleware in the stack.

If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will hang permanently.

---

2. Learning Objectives

By the end of this chapter, you will be able to:

  • Define what middleware is in the context of Express.
  • Write custom middleware functions.
  • Understand the importance of the next() function.
  • Apply middleware globally using app.use().
  • Apply middleware locally to specific routes.
  • Build a custom request logger middleware.

---

3. Beginner-Friendly Explanations

The Request Pipeline

When a request hits your server, it enters a "pipeline."
  1. 1. Request arrives.
  1. 2. Goes through Middleware 1 (e.g., checks if the user is logged in). Calls next().
  1. 3. Goes through Middleware 2 (e.g., logs the time of the request). Calls next().
  1. 4. Reaches the Route Handler (app.get). Sends the res.send().

If Middleware 1 realizes the user is NOT logged in, it can use res.send("Access Denied") and simply *not* call next(). The pipeline stops, and the route is protected!

---

4. Syntax Explanation

Let's write the simplest possible middleware function.

```javascript id="ch15-syntax-1" const express = require('express'); const app = express();

// A custom middleware function const myLogger = (req, res, next) => { console.log('A new request passed through the middleware!'); // CRITICAL: You must call next(), or the app freezes here. next(); };

// Apply it globally to ALL routes app.use(myLogger);

app.get('/', (req, res) => { res.send('Hello World!'); // This runs AFTER myLogger });

app.listen(3000);

12345678910111213141516171819
**Output Explanation:**
When you visit `http://localhost:3000`, the server first runs `myLogger`, prints the message to the terminal, and then calls `next()`. `next()` tells Express to continue down the file, where it finds `app.get('/')` and sends "Hello World!".

---

## 5. Real-world Examples

**Why is middleware useful?**
- **Authentication:** `const requireLogin = (req, res, next) => { ... }`. You check for a valid session token. If valid, `next()`. If invalid, `res.redirect('/login')`.
- **Parsing Data:** When a user submits an HTML form, Express cannot read it by default. We use a built-in middleware (`express.urlencoded()`) to intercept the raw data, parse it into a JavaScript object, attach it to `req.body`, and call `next()`.
- **CORS:** Adding headers to allow frontend apps (like React) to securely talk to your API.

---

## 6. Multiple Code Examples

### Example 1: Route-Specific Middleware
You don't always want middleware to run on *every* route. You can inject it directly into specific routes.

javascript id="ch15-code-1" const checkAdmin = (req, res, next) => { // Simulating an auth check const isAdmin = false; if (isAdmin) { next(); // Let them through } else { res.status(403).send('Forbidden: You are not an admin.'); } };

// Route without middleware app.get('/public', (req, res) => res.send('Public Page'));

// Route WITH middleware inserted as the 2nd argument! app.get('/dashboard', checkAdmin, (req, res) => { res.send('Welcome to the secret admin dashboard!'); });

123
### Example 2: Modifying the `req` object
Middleware can add new data to the `req` object. When it calls `next()`, the route handler will have access to that new data!

javascript id="ch15-code-2" const addTimestamp = (req, res, next) => { // Adding a custom property to the req object req.requestTime = new Date().toLocaleTimeString(); next(); };

app.use(addTimestamp);

app.get('/', (req, res) => { // We can access the property created by the middleware! res.send(You requested this page at: ${req.requestTime}); });

123
### Example 3: Built-in Express Middleware
Express comes with some essential middleware built-in. You've already seen how to serve 404 pages. Let's look at another one used to serve static files (like CSS or images).

javascript id="ch15-code-3" // This built-in middleware tells Express to automatically // serve any files placed in the 'public' folder. app.use(express.static('public'));

1234567891011121314151617181920212223242526272829303132333435363738394041
---

## 7. Output Explanations

The order of `app.use()` is extremely important. 
If you write `app.get('/')` at the top of your file, and `app.use(myLogger)` *below* it, the logger will **not** run when you visit `/`. Express evaluates requests from top to bottom. Once a route sends a response (`res.send`), the cycle is over, and code below it is ignored. Global middleware should always go at the very top!

---

## 8. Common Mistakes

1. **Forgetting `next()`:** This is the #1 beginner mistake. Your browser will show a spinning loading icon forever because the server never sent a response and never passed control to the route that does.
2. **Calling `next()` after sending a response:** 
   ```javascript
   res.send("Stop");
   next(); // ERROR! Cannot continue after sending response.
   ```
3. **Wrong Order:** Placing a critical authentication middleware at the bottom of the file instead of the top, leaving all your routes unprotected.

---

## 9. Best Practices

- **Keep Middleware focused:** A middleware function should do one specific thing (e.g., logging, or authenticating, or parsing). Don't write a massive 100-line middleware that does everything.
- **Use Third-Party Middleware:** Don't write your own logging or CORS middleware for production. Use tested NPM packages like `morgan` (for logging) and `cors` (for security).

---

## 10. Exercises

1. Write a middleware function called `logMethod` that logs `req.method` (e.g., "GET") to the terminal, and then calls `next()`.
2. Apply `logMethod` globally using `app.use()`.
3. Create a route to test that it works.

---

## 11. Mini Project: Request logger app

**Objective:** Build an advanced custom logger that records the method, URL, and exact time of every incoming request.

**Code (`loggerApp.js`):**

javascript id="ch15-mini-project" // loggerApp.js const express = require('express'); const app = express();

// 1. Define the Custom Middleware const requestLogger = (req, res, next) => { const time = new Date().toISOString(); const method = req.method; const url = req.url; console.log([${time}] ${method} request to ${url}); // Pass control to the next function next(); };

// 2. Apply Middleware Globally (Must be at the top!) app.use(requestLogger);

// 3. Define Routes app.get('/', (req, res) => { res.send("<h1>Home Page</h1>"); });

app.get('/products', (req, res) => { res.send("<h1>Products Page</h1>"); });

// 4. Start Server app.listen(3000, () => { console.log('Server running. Check terminal for logs.'); }); ``

Run it: node loggerApp.js Visit /, then visit /products, then visit /fake-page. Watch your terminal log every single interaction!

---

12. Coding Challenges

Challenge 1: Create an ageRestriction middleware. It should check if req.query.age is greater than or equal to 18. If yes, call next(). If no, res.send("Too young"). Apply this middleware *only* to a route named /vip. (Test it using URLs like /vip?age=15 and /vip?age=20).

Challenge 2: Install the NPM package morgan. Read its documentation, and replace your custom requestLogger with Morgan's app.use(morgan('dev')) middleware.

---

13. MCQs with Answers

Q1: What is the primary purpose of the next() function in middleware? A) To send a response to the client. B) To pass control to the next middleware or route handler in the pipeline. C) To restart the server. D) To skip the current request. Answer: B

Q2: If a middleware function does NOT call next() and does NOT send a response, what happens? A) The server crashes. B) Node.js automatically calls next(). C) The client's request hangs and times out. D) Express sends a 404 error. Answer: C

Q3: How do you apply a middleware function globally to all routes? A) app.all(middleware) B) app.global(middleware) C) app.use(middleware) D) express.middleware(middleware) Answer: C

Q4: Can a middleware function modify the req object before it reaches the route handler? A) Yes B) No Answer: A

---

14. Interview Questions

  1. 1. What is Express Middleware?
*Answer:* Middleware functions are functions that intercept incoming HTTP requests. They have access to the
req and res objects, and a next function. They are used to execute code, modify request/response objects, handle errors, or terminate the request early (like for authentication).
  1. 2. Why is the order of app.use() important?
*Answer:* Express executes middleware in the exact order they are defined in the file. If a route handler (like app.get) matches the request and sends a response before a middleware is defined, that middleware will never execute.

---

15. FAQs

Q: Are route handlers (like app.get('/', (req, res) => {})) considered middleware? A: Yes! Technically, route handlers are just middleware functions that are restricted to a specific HTTP method and path, and they usually end the cycle by sending a response rather than calling next().

Q: How many middleware functions can I chain together? A: As many as you want! You can pass an array of middlewares to a route: app.get('/route', [mid1, mid2, mid3], handler);.

---

16. Summary

  • Middleware intercepts requests in the Express pipeline.
  • It has access to req, res, and next.
  • You must call next() to continue the pipeline, or end it with a response.
  • Use app.use(middleware)` to apply it globally.
  • Global middleware must be placed at the top of your file.

---

17. Next Chapter Recommendation

Now that we understand routing and middleware, let's talk about the frontend. How do we serve CSS, JavaScript, and images to the browser? In Chapter 16: Serving Static Files in Express, we will use a built-in middleware to easily host an entire static portfolio website!

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·