Node.js8 min read

Express Middleware Explained

Understand Express middleware - functions that process requests. Learn to create and use middleware effectively.

Sarah Chen
December 19, 2025
0.0k0

Express Middleware Explained

Middleware = functions that run between request and response. They're Express's superpower.

What is Middleware?

function middleware(req, res, next) {
  // Do something with request
  console.log('Request received');
  
  // Pass to next middleware
  next();
}

The Request Flow

Request → Middleware 1 → Middleware 2 → Route Handler → Response

Using Middleware

const express = require('express');
const app = express();

// Apply to ALL routes
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

// Apply to specific path
app.use('/api', (req, res, next) => {
  console.log('API request');
  next();
});

// Routes
app.get('/', (req, res) => res.send('Home'));

Built-in Middleware

// Parse JSON bodies
app.use(express.json());

// Parse URL-encoded bodies (form data)
app.use(express.urlencoded({ extended: true }));

// Serve static files
app.use(express.static('public'));

Creating Custom Middleware

Logger:

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

app.use(logger);

Request Timer:

function timer(req, res, next) {
  req.startTime = Date.now();
  
  res.on('finish', () => {
    const duration = Date.now() - req.startTime;
    console.log(`Request took ${duration}ms`);
  });
  
  next();
}

app.use(timer);

Auth Check:

function requireAuth(req, res, next) {
  const token = req.headers.authorization;
  
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  // Verify token...
  req.user = { id: 1, name: 'Alice' };
  next();
}

// Use on specific routes
app.get('/api/profile', requireAuth, (req, res) => {
  res.json(req.user);
});

Order Matters!

// ✅ Correct - body parser before routes
app.use(express.json());
app.post('/data', (req, res) => {
  console.log(req.body);  // Works!
});

// ❌ Wrong - body parser after route
app.post('/data', (req, res) => {
  console.log(req.body);  // undefined!
});
app.use(express.json());

Error Handling Middleware

// Regular middleware has 3 params
// Error middleware has 4 (err first)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something broke!' });
});

// Trigger error
app.get('/error', (req, res, next) => {
  next(new Error('Oops!'));
});

Third-Party Middleware

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

app.use(cors());           // Enable CORS
app.use(helmet());         // Security headers
app.use(morgan('dev'));    // Request logging

Middleware Factory

function rateLimit(maxRequests, windowMs) {
  const requests = new Map();
  
  return (req, res, next) => {
    const ip = req.ip;
    const now = Date.now();
    
    if (!requests.has(ip)) {
      requests.set(ip, []);
    }
    
    const userRequests = requests.get(ip)
      .filter(time => now - time < windowMs);
    
    if (userRequests.length >= maxRequests) {
      return res.status(429).json({ error: 'Too many requests' });
    }
    
    userRequests.push(now);
    requests.set(ip, userRequests);
    next();
  };
}

// 100 requests per minute
app.use(rateLimit(100, 60000));

Key Takeaway

Middleware processes requests in order. Always call next() to continue the chain. Use built-in middleware for JSON/forms, third-party for logging/security, and custom for app-specific logic. Put them before your routes!

#Node.js#Express#Middleware#Intermediate