How does middleware work in Express?
Tags: node, express, middleware
Published: 2021-05-10 12:12:19

---
title: How does middleware work in Express?
published: true
date: 2021-05-10 12:11:00 UTC
tags: node,express,middleware
canonical_url: https://simonplend.com/how-does-middleware-work-in-express/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m48uwpssyt844thdovsj.png
---

*This article is an adapted excerpt from my book, [Express API Validation Essentials](https://expressapivalidation.com/). It teaches you a complete API validation strategy which you can start applying in your Express applications today.*

---

The Express documentation tells us that "an Express application is essentially a series of middleware function calls". It sounds simple on the surface, but honestly, middleware can get pretty confusing. You've probably found yourself wondering:

- Where is the right place to add this middleware in my application?
- When should I call the `next` callback function, and what happens when I do?
- Why does the order of middleware matter?
- How can I write my own code for handling errors?

The middleware pattern is fundamental to building applications with Express, so you want to have a solid understanding of what middleware is and how it works.

In this article we're going to dig into the middleware pattern. We'll also look at the different types of Express middleware and how to effectively combine them when we build our applications.

## Jump links

- [The middleware pattern](#the-middleware-pattern)
	- [Middleware syntax](#middleware-syntax)
- [The two types of middleware](#the-two-types-of-middleware)
	- [Plain middleware](#plain-middleware)
	- [Error handling middleware](#error-handling-middleware)
- [Using middleware](#using-middleware)
	- [At the route level](#at-the-route-level)
	- [At the router level](#at-the-router-level)
	- [At the application level](#at-the-application-level)
- [Wrapping up](#wrapping-up)

## The middleware pattern

In Express, middleware are a specific style of function which you configure your application to use. They can run any code you like, but they typically take care of processing incoming requests, sending responses and handling errors. They are the building blocks of every Express application.

When you define a route in Express, the route handler function which you specify for that route is a middleware function:

```javascript
app.get("/user", function routeHandlerMiddleware(request, response, next) {
	// execute something
});
```

_(Example 1.1)_

Middleware is flexible. You can tell Express to run the same middleware function for different routes, enabling you to do things like making a common check across different API endpoints.

As well as writing your own middleware functions, you can also install third-party middleware to use in your application. The Express documentation lists some [popular middleware modules](https://expressjs.com/en/resources/middleware.html). There are also a wide variety of Express middleware modules available on [npm](https://www.npmjs.com/).

### Middleware syntax

Here is the syntax for a middleware function:

```javascript
/**
 * @param {Object} request - Express request object (commonly named `req`)
 * @param {Object} response - Express response object (commonly named `res`)
 * @param {Function} next - Express `next()` function
 */
function middlewareFunction(request, response, next) {
	// execute something
}
```

_(Example 1.2)_

> *Note: You might have noticed that I refer to `req` as `request` and `res` as `response`. You can name the parameters for your middleware functions whatever you like, but I prefer verbose variable names as I think that it makes it easier for other developers to understand what your code is doing, even if they're not familiar with the Express framework.*

When Express runs a middleware function, it is passed three arguments:

- An Express request object (commonly named `req`) - this is an extended instance of Node.js' built-in [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) class.
- An Express response object (commonly named `res`) - this is an extended instance of Node.js' built-in [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) class.
- An Express `next()` function - Once the middleware function has completed its tasks, it must call the `next()` function to hand off control to the next middleware. If you pass an argument to it, Express assumes it to be an error. It will skip any remaining non-error handling middleware functions and start executing error handling middleware.

Middleware functions should not `return` a value. Any value returned by middleware will not be used by Express.

## The two types of middleware

### Plain middleware

Most middleware functions that you will work with in an Express application are what I call "plain" middleware (the Express documentation doesn't have a specific term for them). They look like the function defined in the middleware syntax example above (_Example 1.2_).

Here is an example of a plain middleware function:

```javascript
function plainMiddlewareFunction(request, response, next) {
	console.log(`The request method is ${request.method}`);

	/**
	 * Ensure the next middleware function is called.
	 */
	next();
}
```

_(Example 1.3)_

### Error handling middleware

The difference between [error handling middleware](https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling) and plain middleware is that error handler middleware functions specify four parameters instead of three i.e. `(error, request, response, next)`.

Here is an example of an error handling middleware function:

```javascript
function errorHandlingMiddlewareFunction(error, request, response, next) {
	console.log(error.message);

	/**
	 * Ensure the next error handling middleware is called.
	 */
	next(error);
}
```

_(Example 1.4)_

This error handling middleware function will be executed when another middleware function calls the `next()` function with an error object e.g.

```javascript
function anotherMiddlewareFunction(request, response, next) {
	const error = new Error("Something is wrong");

	/**
	 * This will cause Express to start executing error
	 * handling middleware.
	 */
	next(error);
}
```

_(Example 1.5)_

## Using middleware

The order in which middleware are configured is important. You can apply them at three different levels in your application:

- The route level
- The router level
- The application level

If you want a route (or routes) to have errors which they raise handled by an error handling middleware, you must add it after the route has been defined.

Let's look at what configuring middleware looks like at each level.

### At the route level

This is the most specific level: any middleware you configure at the route level will only run for that specific route.

```javascript
app.get("/", someMiddleware, routeHandlerMiddleware, errorHandlerMiddleware);
```

_(Example 1.6)_

### At the router level

Express allows you to create [Router](https://expressjs.com/en/api.html#router) objects. They allow you to scope middleware to a specific set of routes. If you want the same middleware to run for multiple routes, but not for all routes in your application, they can be very useful.

```javascript
import express from "express";

const router = express.Router();

router.use(someMiddleware);

router.post("/user", createUserRouteHandler);
router.get("/user/:user_id", getUserRouteHandler);
router.put("/user/:user_id", updateUserRouteHandler);
router.delete("/user/:user_id", deleteUserRouteHandler);

router.use(errorHandlerMiddleware);
```

_(Example 1.7)_

### At the application level

This is the least specific level. Any middleware configured at this level will be run for all routes.

```javascript
app.use(someMiddleware);

// define routes

app.use(errorHandlerMiddleware);
```

_(Example 1.8)_

Technically you can define some routes, call `app.use(someMiddleware)` , then define some other routes which you want `someMiddleware` to be run for. I don't recommend this approach as it tends to result in a confusing and hard to debug application structure.

You should only configure middleware at the application level if absolutely necessary i.e. it really must be run for every single route in your application. Every middleware function, no matter how small, takes *some* time to execute. The more middleware functions that need to be run for a route, the slower requests to that route will be. This really adds up as your application grows and is configured with lots of middleware. Try to scope middleware to the route or router levels when you can.

## Wrapping up

In this article we've learnt about the middleware pattern in Express. We've also learnt about the different types of middleware and how we can combine them when building an application with Express.

If you'd like to read more about middleware, there are a couple of guides in the Express documentation:

- [Guide: Using middleware](https://expressjs.com/en/guide/using-middleware.html)
- [Guide: Writing middleware for use in Express apps](https://expressjs.com/en/guide/writing-middleware.html)

---

*This article is an adapted excerpt from my book, [Express API Validation Essentials](https://expressapivalidation.com/). It teaches you a complete API validation strategy which you can start applying in your Express applications today.*

---

## Tired of wasting time reading Node.js blog posts which don't actually help you improve your projects?

[Sign up to my weekly-ish newsletter](https://simonplend.com/newsletter/) and I'll let you know when I publish a new blog post which helps solve your real developer problems. I'll also send you an awesome tip so we can level up together, as well as a handful of excellent things by other people.