How to handle middleware in Express
Middleware functions are the backbone of Express applications, providing a way to process requests before they reach route handlers. With over 25 years of experience in backend development and as the creator of CoreUI, I’ve built countless APIs that rely on middleware for authentication, logging, and data processing. The most effective approach is using app.use() to register middleware functions that execute in order for each request. This pattern provides modularity, reusability, and clean separation of concerns in your Express application.
Use app.use() to register middleware functions that process requests before they reach your route handlers.
const express = require('express')
const app = express()
// Global logging middleware
app.use((req, res, next) => {
console.log(`${req.method} ${req.path} - ${new Date().toISOString()}`)
next()
})
// JSON parsing middleware
app.use(express.json())
// Authentication middleware for protected routes
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization
if (!token) {
return res.status(401).json({ error: 'No token provided' })
}
// Verify token logic here
next()
}
// Apply auth middleware to specific routes
app.use('/api/protected', authMiddleware)
app.get('/api/protected/users', (req, res) => {
res.json({ users: ['John', 'Jane'] })
})
This example demonstrates three types of middleware: global logging middleware that runs for all requests, built-in JSON parsing middleware, and custom authentication middleware applied to specific route paths. Each middleware function receives req, res, and next parameters, where next() passes control to the next middleware in the chain.
Best Practice Note:
This middleware pattern is used extensively in CoreUI’s backend templates for consistent request processing and security. Always call next() unless you’re ending the response, and place middleware in the correct order since they execute sequentially.



