Writing Custom Middleware
Build your own middleware to add reusable behavior to your app.
Syntax
function mw(options) { return (req, res, next) => { ... }; }Custom middleware is just a function that takes req, res and next. You can attach data to req, check conditions, and either respond or call next().
A common pattern is a middleware factory: a function that returns a middleware, so you can configure it. The example creates a role checker you can reuse on any route.
Example
function requireRole(role) {
return (req, res, next) => {
if (req.headers['x-role'] !== role) {
return res.status(403).send('Forbidden');
}
next();
};
}
app.get('/admin', requireRole('admin'), (req, res) => {
res.send('Welcome, admin');
});When to use it
- A team writes a custom requestId middleware that generates a UUID per request and attaches it to req and to the response header for tracing.
- A developer creates a custom middleware that checks a plan tier stored on req.user and blocks calls that exceed the rate limit for that tier.
- A middleware reads a tenant ID from the subdomain in req.hostname and attaches the tenant's database connection to req for all downstream handlers.
More examples
Request ID middleware
Generates a UUID, attaches it to req.id, and also sets it on the response header for client-side tracing.
const { randomUUID } = require('crypto');
function requestId(req, res, next) {
req.id = randomUUID();
res.setHeader('X-Request-Id', req.id);
next();
}
app.use(requestId);
app.get('/', (req, res) => res.json({ id: req.id }));Timing middleware
Uses the res 'finish' event to measure and log the total time taken for every request-response cycle.
function responseTime(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const ms = Date.now() - start;
console.log(`${req.method} ${req.path} — ${ms}ms`);
});
next();
}
app.use(responseTime);Tenant context middleware
Extracts the subdomain from req.hostname, looks up the matching tenant config, and attaches it to req.tenant.
const tenants = { acme: { db: 'acme_db' }, beta: { db: 'beta_db' } };
function resolveTenant(req, res, next) {
const host = req.hostname; // e.g. acme.myapp.com
const subdomain = host.split('.')[0];
req.tenant = tenants[subdomain];
if (!req.tenant) return res.status(404).json({ error: 'Unknown tenant' });
next();
}
app.use(resolveTenant);
Discussion