Middleware is a crucial part of any Laravel application, acting as a bridge between HTTP requests and responses. With Laravel 11 introducing some refinements, it’s a great time to explore how middleware works, how to create custom middleware, and best practices for using it effectively.
What is Middleware?
Middleware provides a convenient way to filter and modify HTTP requests entering your application. It can perform tasks such as:
- Authenticating users
- Logging requests
- Applying CORS headers
- Rate limiting
- Redirecting based on conditions
Each middleware runs before or after the request reaches the application’s core logic, making it a powerful tool for request processing.
Middleware in Laravel 11
Laravel 11 continues to support middleware as in previous versions but with optimizations for better performance and readability. The key concepts remain the same:
- Global Middleware — Runs on every HTTP request.
- Route Middleware — Assigned to specific routes or groups.
- Middleware Groups — Bundles multiple middleware under a single name (e.g., web, api).
Creating Custom Middleware in Laravel 11
Let’s create a custom middleware that checks if a user is an admin.
Step 1: Generate Middleware
Use the Artisan command:
php artisan make:middleware EnsureIsAdminThis creates app/Http/Middleware/EnsureIsAdmin.php.
Step 2: Implement Logic
Modify the handle method:
<?php namespace App\Http\Middleware;use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;class EnsureIsAdmin
{
public function handle(Request $request, Closure $next): Response
{
if (!auth()->user() || !auth()->user()->is_admin) {
return redirect('/')->with('error', 'You are not authorized!');
} return $next($request);
}
}
Step 3: Register Middleware
Add it to app/Http/Kernel.php under the $routeMiddleware array:
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\EnsureIsAdmin::class,
// Other middleware...
];Step 4: Apply Middleware to Routes
Use it in routes/web.php:
Route::get('/admin/dashboard', function () {
return view('admin.dashboard');
})->middleware('admin');Or apply it to a route group:
Route::middleware(['admin'])->group(function () {
Route::get('/admin/dashboard', 'AdminController@dashboard');
Route::get('/admin/users', 'AdminController@users');
});Middleware Groups in Laravel 11
Laravel 11 includes predefined middleware groups (web, api) in app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
// Other web middleware...
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
// Other API middleware...
],
];Using Middleware Groups
// Apply 'web' middleware group (default for web routes)
Route::middleware('web')->group(function () {
Route::view('/profile', 'profile');
});
// Apply 'api' middleware group
Route::middleware('api')->group(function () {
Route::get('/api/posts', 'PostController@index');
});Middleware Parameters
You can pass parameters to middleware for dynamic behavior.
Example: Role-Based Middleware
- Modify Middleware (app/Http/Middleware/CheckRole.php):
public function handle(Request $request, Closure $next, string $role)
{
if (!auth()->user() || auth()->user()->role !== $role) {
abort(403, 'Unauthorized');
}
return $next($request);
}- Register in Kernel.php:
protected $routeMiddleware = [
'role' => \App\Http\Middleware\CheckRole::class,
];- Use in Routes:
Route::get('/admin', function () {
return 'Admin Dashboard';
})->middleware('role:admin');Terminable Middleware
If a middleware needs to perform actions after the response is sent, implement the Terminable interface:
class LogRequestTime implements TerminableMiddleware
{
public function handle(Request $request, Closure $next)
{
return $next($request);
}
public function terminate(Request $request, Response $response)
{
Log::info('Request completed at: ' . now());
}
}Best Practices for Middleware in Laravel 11
- Keep Middleware Lightweight — Avoid heavy logic inside middleware.
- Use Middleware Groups — Group related middleware for cleaner routes.
- Apply Middleware Strategically — Only use middleware where necessary.
- Leverage Middleware Parameters — Make middleware reusable with dynamic values.
- Test Middleware — Write unit tests to ensure middleware behaves as expected.
Conclusion
Middleware in Laravel 11 remains a powerful tool for handling HTTP requests efficiently. Whether you’re authenticating users, logging requests, or applying CORS policies, middleware helps keep your application clean and modular. By following best practices and leveraging Laravel’s middleware groups and parameters, you can build secure and scalable applications.
What’s your favorite middleware use case? Let me know in the comments! 🚀