Middleware in Laravel 12: A Step-by-Step Guide

Sandeeppant
4 min readMar 29, 2025

--

Starting in Laravel 11, the configuration of the middleware changed from using the HTTP Kernel to the application’s bootstrap file. Though some existing applications upgraded from Laravel 10 to Laravel 11 and 12 might have middleware defined, a new Laravel application doesn’t ship with an app/Http/Middlewares folder:

Laravel 11 introduces a new default application structure with fewer default files. Namely, new Laravel applications contain fewer service providers, middleware, and configuration files.

#Configuring Middleware in Laravel 11+

As of Laravel 11 the Kernel class isn't part of the application code. Here's an example of defining a global middleware:

// bootstrap/app.php

use App\Http\Middleware\LogRequest;

->withMiddleware(function (Middleware $middleware) {
// Append to the end of the middleware stack
$middleware->append(LogRequest::class);
})

If you would like to add global middleware to the beginning of the stack, you can use the prepend method:

use App\Http\Middleware\LogRequest;

->withMiddleware(function (Middleware $middleware) {
// Add middleware to the beginning of the middleware stack
$middleware->prepend(LogRequest::class);
})

#Defining Middleware Groups:

In new Laravel applications, you can use the prepend/append to group methods:

$middleware->prependToGroup('group-1', First::class);

$middleware->appendToGroup('group-1', [
First::class,
Second::class,
);

You might also wonder: “How do I customize one of the built-in groups like web or API ?" You can do so with the respective web and api methods:

$middleware->web(append: [
ExampleWebMiddleware::class,
]);

$middleware->api(prepend: [
ExampleApiMiddleware::class,
]);

$middleware->api(remove: [
ExampleApiMiddleware::class,
]);

#Sorting Middleware:

From Laravel 11+ , you can configure priority using the bootstrap app.php file using the priority method:

->withMiddleware(function (Middleware $middleware) {
$middleware->priority([
//
]);

#Middleware Aliases:

Starting in Laravel 11, you can use the alias method to map an alias string name to a middleware so you can conveniently add middleware to routes and groups.

->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'log' => LogRequest::class
]);
});

// In a route you can use `log`
Route::get('/messages/{message}', function () {
// ...
})->middleware('log');

#Middleware Parameters:

Middleware can also receive additional parameters. For example, if your application needs to verify that the authenticated user has a given “role” before performing a given action, you could create an EnsureUserHasRole middleware that receives a role name as an additional argument.

Additional middleware parameters will be passed to the middleware after the $next argument:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}

return $next($request);
}

}

Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a ‘:':

use App\Http\Middleware\EnsureUserHasRole;

Route::put('/post/{id}', function (string $id) {
// ...
})->middleware(EnsureUserHasRole::class.':editor');

Multiple parameters may be delimited by commas:

Route::put('/post/{id}', function (string $id) {
// ...
})->middleware(EnsureUserHasRole::class.':editor,publisher');

#Terminable Parameters:

If you add a terminate method to your middleware in Laravel, it will run after the response is sent to the browser, but this only happens automatically if you're using FastCGI as your web server.

<?php

namespace Illuminate\Session\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class TerminatingMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}

/**
* Handle tasks after the response has been sent to the browser.
*/
public function terminate(Request $request, Response $response): void
{
// ...
}
}

when you define a terminate method in your middleware, it should accept both the request and the response. After defining the terminable middleware, you need to add it to the routes or global middleware list in the bootstrap/app.php file.

When the terminate method is called, Laravel creates a new instance of the middleware from the service container. If you want to use the same instance for both the handle and terminate methods, register the middleware as a singleton in the service container, usually in the register method of your AppServiceProvider.

use App\Http\Middleware\TerminatingMiddleware;

/**
* Register any application services.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}

#Assigning and Excluding Middleware from Route:

If you would like to assign middleware to specific routes, you may invoke the middleware method when defining the route:

use App\Http\Middleware\EnsureTokenIsValid;

Route::get('/profile', function () {
// ...
})->middleware(EnsureTokenIsValid::class);

You may assign multiple middleware to the route by passing an array of middleware names to the middleware method:

Route::get('/', function () {
// ...
})->middleware([First::class, Second::class]);

Sometimes, you may occasionally need to prevent the middleware from being applied to an individual route within the group. You may accomplish this using the withoutMiddleware method:

use App\Http\Middleware\EnsureTokenIsValid;

Route::middleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/', function () {
// ...
});

Route::get('/profile', function () {
// ...
})->withoutMiddleware([EnsureTokenIsValid::class]);
});

You may also exclude a given set of middleware from an entire group of route definitions:

use App\Http\Middleware\EnsureTokenIsValid;

Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/profile', function () {
// ...
});
});

withoutMiddleware method doenot apply to global middleware.

Thank you for Reading …..

Before you go don’t forget to clap, share and follow me 😇😇😇

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response