Express Cheatsheet
Middleware
Use this Express reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
What Is Middleware
A middleware function has the signature (req, res, next) (or (err, req, res, next) for errors). It runs in order, must call next() to continue, or end the response itself.
// Minimal middleware const logger = (req, res, next) => { console.log(`${req.method} ${req.url}`); next(); // pass control to next middleware or route };
app.use() — Mounting Middleware
// Apply to ALL routes, ALL methods app.use(logger); // Apply to all routes under /api app.use('/api', logger); // Multiple middleware in one call app.use(express.json(), express.urlencoded({ extended: true }), logger); // Array app.use([cors(), helmet(), logger]);
Middleware Execution Order
Order of app.use() and route registrations defines execution order — registration order is matching order.
app.use(parseBody); // 1st: runs for every request app.use(authenticate); // 2nd app.get('/public', publicHandler); // only for GET /public app.use(authorise); // 3rd: runs after publicHandler app.get('/admin', adminHandler); app.use(notFoundHandler); // last: 404 fallback
Types of Middleware
Application-Level
app.use((req, res, next) => { /* runs on every request */ next(); }); app.use('/path', (req, res, next) => { /* runs only under /path */ next(); });
Router-Level
const router = express.Router(); router.use((req, res, next) => { /* scoped to this router */ next(); });
Error-Handling
Must have exactly four parameters — Express detects the arity.
app.use((err, req, res, next) => { console.error(err.stack); res.status(err.status || 500).json({ error: err.message }); });
Trigger with next(err) or next(new Error('something')) from any handler.
Third-Party
const morgan = require('morgan'); const cors = require('cors'); const helmet = require('helmet'); app.use(morgan('combined')); app.use(cors()); app.use(helmet());
Built-In (Express 4.16+)
| Middleware | Purpose |
|---|---|
express.json(options) | Parse application/json bodies |
express.urlencoded(options) | Parse application/x-www-form-urlencoded |
express.raw(options) | Parse body as Buffer |
express.text(options) | Parse body as string |
express.static(root, options) | Serve static files |
Conditional Middleware
// Skip in test environment if (process.env.NODE_ENV !== 'test') { app.use(morgan('dev')); } // Skip for a specific path app.use((req, res, next) => { if (req.path === '/health') return next(); return authenticate(req, res, next); }); // Express-unless pattern (common helper) const unless = (path, middleware) => (req, res, next) => req.path === path ? next() : middleware(req, res, next); app.use(unless('/login', authenticate));
Writing Reusable Middleware (Factory Pattern)
Return a middleware function from a factory for configurable behavior.
const rateLimit = (limit, windowMs) => { const counts = new Map(); return (req, res, next) => { const key = req.ip; const now = Date.now(); const entry = counts.get(key) || { count: 0, start: now }; if (now - entry.start > windowMs) { entry.count = 0; entry.start = now; } entry.count++; counts.set(key, entry); if (entry.count > limit) { return res.status(429).json({ error: 'Too many requests' }); } next(); }; }; app.use('/api', rateLimit(100, 60_000));
Async Middleware
Express 4 does not catch rejected promises automatically — wrap or use a helper.
// Manual try/catch app.use(async (req, res, next) => { try { req.user = await findUser(req.headers.authorization); next(); } catch (err) { next(err); } }); // Async wrapper utility const asyncHandler = fn => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); app.get('/users', asyncHandler(async (req, res) => { const users = await db.query('SELECT * FROM users'); res.json(users); }));
Express 5 automatically forwards rejected promises to
next(err)— no wrapper needed.
Modifying req and res in Middleware
// Attach data to req for downstream handlers app.use(async (req, res, next) => { req.requestId = crypto.randomUUID(); req.startTime = Date.now(); next(); }); // Wrap res.json to add envelope app.use((req, res, next) => { const originalJson = res.json.bind(res); res.json = (data) => originalJson({ data, requestId: req.requestId }); next(); });
Middleware Short-Circuiting
const authenticate = (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' }); // end here try { req.user = jwt.verify(token, process.env.JWT_SECRET); next(); // continue } catch { res.status(401).json({ error: 'Invalid token' }); // end here } };
Common Third-Party Middleware
| Package | Purpose | Usage |
|---|---|---|
morgan | HTTP request logger | app.use(morgan('dev')) |
cors | CORS headers | app.use(cors(options)) |
helmet | Security headers | app.use(helmet()) |
compression | Gzip responses | app.use(compression()) |
multer | File uploads (multipart) | router.post('/', upload.single('file'), handler) |
express-rate-limit | Rate limiting | app.use('/api', rateLimit({ windowMs, max })) |
express-validator | Input validation | [body('email').isEmail(), validationResult] |
cookie-parser | Parse cookies | app.use(cookieParser(secret)) |
express-session | Session support | app.use(session({ secret, resave, saveUninitialized })) |
passport | Authentication strategies | app.use(passport.initialize()) |