Run It Only Sometimes
Conditional Middleware
Apply middleware only when a condition holds — by path, method, or env.
What you'll learn
- Skip middleware conditionally
- Apply only in specific environments
- Use mounting paths effectively
Sometimes middleware should fire only under some conditions — specific paths, environments, or methods.
By Mount Path
The simplest filter — Express’s built-in:
app.use("/admin", requireAdmin); // only on /admin/*
app.use("/api", express.json()); // only on /api/*
app.use("/api/v2/uploads", express.raw()); // very specific By Predicate — Skip Inside
function devOnly(mw) {
return (req, res, next) => {
if (process.env.NODE_ENV !== "development") return next();
return mw(req, res, next);
};
}
app.use(devOnly(morgan("dev"))); Same idea — wrap and decide.
By Method
function onlyMutating(mw) {
return (req, res, next) => {
if (["GET", "HEAD", "OPTIONS"].includes(req.method)) return next();
return mw(req, res, next);
};
}
app.use(onlyMutating(csrfProtection)); CSRF protection only matters for state-changing methods. Skip GET/HEAD/OPTIONS.
A Reusable Helper
function when(predicate, mw) {
return (req, res, next) => {
if (predicate(req)) return mw(req, res, next);
return next();
};
}
app.use(when(
(req) => req.path.startsWith("/api"),
authenticate
)); Disable in Tests
if (process.env.NODE_ENV !== "test") {
app.use(rateLimit({ /* ... */ }));
} Stops the rate-limit middleware from polluting test runs.
Avoid Heavy Conditionals
Conditionals inside middleware are a hint that you might want to split the route or mount under a different path. The clearest Express code has flat, declarative middleware — each one with one job.
Per-Route Middleware →