Using Middleware in Express.js: A Complete and Practical Guide

Using Middleware in Express.js: A Complete and Practical Guide

Express MiddlewareApplication-level MiddlewareRouter-level MiddlewareError-handling MiddlewareBuilt-in MiddlewareThird-party Middleware

~3 min read · Updated Dec 26, 2025

1. What Is Middleware?


A middleware function in Express has access to:

  • req – the request object
  • res – the response object
  • next – a function that passes control to the next middleware

Middleware can:

  • Execute any code
  • Modify req or res
  • End the request–response cycle
  • Call next() to continue the chain

If a middleware does not end the response, it must call next(), otherwise the request will hang.

2. Types of Middleware in Express


  • Application-level middleware
  • Router-level middleware
  • Error-handling middleware
  • Built-in middleware
  • Third-party middleware

3. Application-Level Middleware


3.1 Middleware Without a Mount Path

app.use((req, res, next) => {
  console.log('Time:', Date.now())
  next()
})

3.2 Middleware With a Mount Path

app.use('/user/:id', (req, res, next) => {
  console.log('Request Type:', req.method)
  next()
})

3.3 Route Handler as Middleware

app.get('/user/:id', (req, res) => {
  res.send('USER')
})

3.4 Middleware Sub-stack

app.use('/user/:id',
  (req, res, next) => {
    console.log('Request URL:', req.originalUrl)
    next()
  },
  (req, res, next) => {
    console.log('Request Type:', req.method)
    next()
  }
)

4. Multiple Routes for the Same Path


app.get('/user/:id', (req, res, next) => {
  console.log('ID:', req.params.id)
  next()
}, (req, res) => {
  res.send('User Info')
})

app.get('/user/:id', (req, res) => {
  res.send(req.params.id)
})

The second route never runs because the first one ends the response.

5. Skipping Middleware with next('route')


app.get('/user/:id', (req, res, next) => {
  if (req.params.id === '0') next('route')
  else next()
}, (req, res) => {
  res.send('regular')
})

app.get('/user/:id', (req, res) => {
  res.send('special')
})

next('route') only works inside app.METHOD() or router.METHOD().

6. Middleware as an Array


function logOriginalUrl(req, res, next) {
  console.log('Request URL:', req.originalUrl)
  next()
}

function logMethod(req, res, next) {
  console.log('Request Type:', req.method)
  next()
}

const logStuff = [logOriginalUrl, logMethod]

app.get('/user/:id', logStuff, (req, res) => {
  res.send('User Info')
})

7. Router-Level Middleware


Works like application-level middleware but is attached to a Router instance:

const router = express.Router()

router.use((req, res, next) => {
  console.log('Time:', Date.now())
  next()
})

router.use('/user/:id',
  (req, res, next) => {
    console.log('Request URL:', req.originalUrl)
    next()
  },
  (req, res, next) => {
    console.log('Request Type:', req.method)
    next()
  }
)

router.get('/user/:id', (req, res, next) => {
  if (req.params.id === '0') next('route')
  else next()
}, (req, res) => {
  res.render('regular')
})

router.get('/user/:id', (req, res) => {
  res.render('special')
})

app.use('/', router)

Skipping Router Middleware with next('router')

router.use((req, res, next) => {
  if (!req.headers['x-auth']) return next('router')
  next()
})

8. Error-Handling Middleware


Error-handling middleware must have four arguments:

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

9. Built-in Middleware


  • express.static – serves static files
  • express.json – parses JSON bodies
  • express.urlencoded – parses URL-encoded bodies

10. Third-Party Middleware


Example: cookie-parser

npm install cookie-parser

const cookieParser = require('cookie-parser')
app.use(cookieParser())

Conclusion


Middleware is the backbone of Express.js. It controls the flow of requests, enables validation, logging, error handling, and modular architecture. Mastering middleware means mastering Express itself.

Written & researched by Dr. Shahin Siami

Related Articles

Database Integration in Express.js: A Complete Guide to Popular Node.js Database Drivers

Express.js does not include built‑in database support, but its flexibility allows you to connect it to virtually any database system simply by installing the appropriate Node.js driver. This article provides a complete overview of how to integrate Express with many popular SQL and NoSQL databases, including installation commands and example usage.

Continue

Advanced Express.js: Overriding the API, Template Engines, Debugging, and Working Behind Proxies

Advanced Express.js: Overriding the API, Template Engines, Debugging, and Working Behind Proxies

Continue

Overriding the Express API and Using Template Engines

Overriding the Express API and Using Template Engines

Continue

Writing Middleware in Express.js: A Complete Guide for Developers

Middleware is one of the core architectural concepts in Express.js. . Middleware functions have access to the request object (req), the response object (res), and the next() function, which controls the flow of the request–response cycle. Middleware can modify requests, send responses, validate data, log activity, handle errors, or pass control to the next function in the stack. This article explains everything you need to know about writing middleware—from simple examples to async validation, error handling, and configurable middleware.

Continue

Routing in Express.js: A Complete Guide to Application Endpoints

Routing in Express.js defines how an application responds to incoming HTTP requests at specific paths (URIs) and methods. This flexible system allows developers to create simple routes, complex patterns, dynamic parameters, multiple handlers, and modular route structures using Router. This article explains all essential routing concepts—from basic paths to regex routes, route parameters, middleware-style handlers, app.route(), and express.Router.

Continue