Middleware Pipeline
A middleware is any callable shaped function (Request $request, callable $next): Response.
Call $next($request) to continue the pipeline toward the route's action, or return your
own Response to short-circuit it before $next is ever called.
Execution order
Middleware registered first runs outermost — it's the first thing to run on the way in, and the last thing to run on the way out. Middleware registered later sits closer to the route's action:
Route::get('/hello', fn () => Response::text('Hello'))
->middleware(function (Request $request, callable $next): Response {
// runs first, going in
$response = $next($request);
// runs last, coming out
return $response;
})
->middleware(function (Request $request, callable $next): Response {
// runs second, going in — closest to the action
$response = $next($request);
// runs first, coming out
return $response;
});
Group middleware (Route::group(['middleware' => ...], ...)) is prepended before any
route-level middleware added inside the group, and nested groups accumulate their parent's
middleware — see Routing.
Closure or class?
A middleware entry is either an already-callable value (a closure, or an invokable object) used as-is, or a class-string, instantiated with no constructor arguments and invoked directly:
final class AddPoweredByHeader
{
public function __invoke(Request $request, callable $next): Response
{
$response = $next($request);
return $response->withHeader('X-Powered-By', 'Monad');
}
}
Route::get('/hello', fn () => Response::text('Hello'))->middleware(AddPoweredByHeader::class);
The zero-constructor-argument rule is why Clarity's built-in security middlewares
(Csrf, RateLimiter, Authentication, RBAC) are
meant to be registered through a thin subclass in app/Middlewares/ that supplies their
real configuration — the skeleton ships one for each. A closure has no such restriction, since it's
already callable and never gets instantiated by class name.
Every built-in middleware
Csrf— session-token storage, rotation, origin checks.Logger(PSR-3) — request/correlation ID, channel, redaction.Authentication— credential and Google SSO authenticators, remember-me, login throttling.RBAC— role/permission checks, route guards.RateLimiter— required at login, password reset, public API, and LLM call sites.CORS— allowed origins/methods/headers, preflight handling.Jsonify— parses JSON request bodies, feedsRequest::json().MetaTag— meta/OG/Twitter/JSON-LD tag generation for a view's<head>.
Next steps
- Routing — where
->middleware()and group middleware are registered. - Request/Response Lifecycle — where the pipeline fits in the full request-to-response path.