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