Introduction

Middleware is a fundamental concept in Express.js that allows developers to process and manipulate requests before they reach their final destination. Middleware functions provide a way to handle logging, authentication, error handling, and more within Express applications.

In this guide, we’ll explore:

  • What middleware is
  • Types of middleware in Express.js
  • How to create custom middleware
  • Real-world use cases for middleware

By the end of this article, you’ll have a solid understanding of how to use middleware effectively in your Express applications.


1. What is Middleware in Express.js?

Middleware functions in Express.js are functions that execute during the request-response cycle. These functions have access to the request object (req), the response object (res), and the next function, which passes control to the next middleware function.

Middleware Function Syntax:

app.use((req, res, next) => {
    console.log('Middleware function executed');
    next(); // Pass control to the next middleware
});

How Middleware Works

When a request is made to an Express server, it goes through a sequence of middleware functions before sending a response. Each middleware function can:

  • Modify the request (req) and response (res) objects
  • End the request-response cycle
  • Call next() to pass control to the next middleware

2. Types of Middleware in Express.js

1. Built-in Middleware

Express provides some built-in middleware functions:

  • express.json() → Parses incoming JSON requests
  • express.urlencoded() → Parses URL-encoded payloads
  • express.static() → Serves static files (CSS, images, JavaScript)

Example:

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

2. Third-Party Middleware

These are middleware functions provided by npm packages. Popular ones include:

  • morgan → Logs HTTP requests
  • cors → Handles Cross-Origin Resource Sharing
  • helmet → Secures apps by setting HTTP headers

Example:

const morgan = require('morgan');
const cors = require('cors');
const helmet = require('helmet');

app.use(morgan('dev'));
app.use(cors());
app.use(helmet());

3. Application-Level Middleware

These middleware functions are applied at the app level and run on every request.

Example:

app.use((req, res, next) => {
    console.log(`Request Method: ${req.method}, Request URL: ${req.url}`);
    next();
});

4. Route-Specific Middleware

Middleware can be applied to specific routes.

Example:

const checkAuth = (req, res, next) => {
    if (req.headers.authorization) {
        next();
    } else {
        res.status(403).send('Unauthorized');
    }
};

app.get('/protected', checkAuth, (req, res) => {
    res.send('You have access!');
});

5. Error-Handling Middleware

This type of middleware is used to catch and handle errors.

Example:

app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('Something went wrong!');
});

3. Creating Custom Middleware in Express

You can create your own middleware functions for tasks like logging, authentication, or modifying request data.

Example: Custom Logging Middleware

const requestLogger = (req, res, next) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next();
};

app.use(requestLogger);

Example: Authentication Middleware

const authenticateUser = (req, res, next) => {
    if (req.headers.authorization === 'secret-token') {
        next();
    } else {
        res.status(401).send('Unauthorized');
    }
};

app.get('/dashboard', authenticateUser, (req, res) => {
    res.send('Welcome to the dashboard');
});

4. Real-World Use Cases for Middleware

Middleware is widely used in Express applications for various purposes:

1. Logging Requests

Using morgan to log HTTP requests:

const morgan = require('morgan');
app.use(morgan('combined'));

2. Handling CORS (Cross-Origin Requests)

Allowing external domains to access your API:

const cors = require('cors');
app.use(cors());

3. Serving Static Files

Serving images, CSS, and JavaScript:

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

4. Error Handling

Catching and handling errors globally:

app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('Internal Server Error');
});

5. Best Practices for Using Middleware

To optimize middleware usage in Express applications, follow these best practices:

  1. Order Matters → Place middleware in the correct sequence, e.g., logging first, then authentication, then routes.
  2. Use Third-Party Middleware → Avoid reinventing the wheel; leverage packages like morgan, helmet, and cors.
  3. Limit Middleware Scope → Apply middleware only where necessary (e.g., route-specific middleware).
  4. Handle Errors Properly → Always include an error-handling middleware at the end of your stack.
  5. Optimize Performance → Minimize unnecessary middleware execution by structuring routes efficiently.

6. Conclusion

Middleware is a powerful feature in Express.js that enhances the functionality, security, and maintainability of web applications. By understanding its types, creating custom middleware, and using third-party solutions, you can build scalable and efficient applications.

Next Steps

  • Implement authentication using JWT middleware.
  • Build a middleware-based rate-limiting system.
  • Optimize error handling for production.

Start experimenting and take your Express skills to the next level! 🚀