0

Middleware priority — the order pipeline executes

Advanced5 min read·lv-07-004
interviewlaravel-src

Concept

Middleware priority determines the execution order within a pipeline. When multiple middleware are applied to a route, they run in the order they appear in the pipeline — but some middleware must run before others regardless of route definition order.

The $middlewarePriority array (in App\Http\Kernel): Defines the relative execution order for middleware in the web and api groups. Middleware listed here runs in the declared order, regardless of how routes define them.

Why priority matters:

  • StartSession must run before Authenticate, because auth needs the session to persist user state.
  • SubstituteBindings must run after route matching but before controllers, so model binding works.
  • VerifyCsrfToken must run after cookies are decrypted but before the request reaches the controller.

Default priority order (roughly):

  1. HandleCors
  2. PreventRequestsDuringMaintenance
  3. EncryptCookies
  4. AddQueuedCookiesToResponse
  5. StartSession
  6. ShareErrorsFromSession
  7. AuthenticateWithBasicAuth
  8. Authenticate
  9. ThrottleRequests
  10. SubstituteBindings
  11. Authorize

Custom middleware ordering: If your custom middleware depends on session or auth, ensure it runs after them by adding it at the appropriate position in $middlewarePriority.

Code Example

php
<?php
// App\Http\Kernel.php — priority array (Laravel ≤ 10)
namespace App\Http;

class Kernel extends \Illuminate\Foundation\Http\Kernel
{
    protected $middlewarePriority = [
        \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Session\Middleware\StartSession::class,    // session first
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class, // then auth
        \Illuminate\Routing\Middleware\ThrottleRequests::class, // rate limit after auth
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class, // binding after auth
        \Illuminate\Auth\Middleware\Authorize::class,           // authz last
    ];
}

// Understanding the order with a concrete example:
// Route: ->middleware(['auth', 'verified', 'can:edit-posts'])
// 1. EncryptCookies (from web group)
// 2. StartSession (from web group — session needed for auth)
// 3. auth (Authenticate — checks session)
// 4. verified (EnsureEmailIsVerified — checks user, needs auth to run first)
// 5. can:edit-posts (Authorize — checks policy, needs auth + model binding)

// Custom middleware that needs to run AFTER session but BEFORE authorize
// Add to $middlewarePriority between StartSession and Authorize:
protected $middlewarePriority = [
    // ...
    \Illuminate\Session\Middleware\StartSession::class,
    \App\Http\Middleware\SetUserLocale::class, // needs session (for stored locale preference)
    // ...
    \Illuminate\Auth\Middleware\Authorize::class,
];

// Checking middleware order in tests
// Use Route::getRoutes() to inspect which middleware are attached
// Or use Artisan: php artisan route:list --path=admin --columns=middleware