Every request tells the same story on its way through the system: it arrives, gets matched to a route, passes through a chain of middleware, and finally produces a response. Understanding that story makes the rest of the codebase easier to read.
Overview
The pipeline is deliberately linear. Each stage only knows about the stage before it and the stage after it, which keeps the whole thing easy to reason about even as individual stages grow more complex.
Routing
Routing decides which handler is responsible for a request before anything else runs.
Static Routes
A static route matches an exact path. These are resolved first, since they’re unambiguous and cheap to check.
Dynamic Routes
A dynamic route matches a pattern with one or more named segments, like /blog/:slug.
Catch-all Segments
A catch-all segment absorbs the rest of the path, which is how a single route can serve an arbitrarily deep tree of pages.
Middleware
Once a route is matched, the request passes through a chain of middleware before reaching the handler.
Built-in Middleware
Built-in middleware handles cross-cutting concerns like logging and error handling, so individual handlers don’t have to.
Custom Middleware
Custom middleware is where project-specific behavior lives, such as authentication checks or request-specific caching rules.
Wrap-up
None of these stages are complicated in isolation. The value is in keeping them separate, so each one can change without the others noticing.
