Course contentsShow
← Node.js
Lesson 636 of 1,9807. Web Framework Architecture and MiddlewareFree lesson

Conditional Middleware Execution

Execute logic only for specific request paths or authenticated user states using predicate functions.

In this lesson, you will learn how to selectively trigger middleware logic based on specific request conditions rather than applying it to every incoming request.

The Problem with Global Middleware

Up until now, we have treated the middleware chain as a linear, one-size-fits-all conveyor belt. Every request that enters your application typically passes through every function you register. However, in a real-world architecture, you rarely want universal logic. You might only want to verify a JWT token on /api routes, or perhaps you want to log details only for POST requests. Applying global middleware to static assets or public health checks creates unnecessary overhead and clutter.

Using Predicate Functions for Control

Conditional middleware execution allows you to "gatekeep" your logic. Instead of just passing (req, res, next) to app.use(), you can wrap your middleware in a higher-order function that acts as a predicate—a function that returns true or false based on the request state.

If the predicate evaluates to true, the middleware executes; if it evaluates to false, it calls next() immediately to skip ahead, effectively bypassing the logic for that specific request.

Consider this example for authenticated routes:

const onlyForAuthenticated = (middleware) => {
  return (req, res, next) => {
    // The predicate: is the user logged in?
    if (req.session && req.session.userId) {
      return middleware(req, res, next);
    }
    // Skip if condition isn't met
    next();
  };
};

// Usage
app.use(onlyForAuthenticated(databaseLogger));

Decoupling Logic from Routing

By using this pattern, you keep your middleware definitions clean and decoupled from your route definitions. You aren't hardcoding path checks (like if (req.path === '/admin')) inside your business logic. Instead, you create reusable wrappers that decide when a piece of code is relevant to the lifecycle of the current request. This keeps your server architecture modular and ensures that expensive operations, like database lookups for session validation, only happen when they are strictly required.

Key Takeaway: Use predicate functions to wrap your middleware, allowing you to selectively execute logic only when specific request conditions or state requirements are met.