What Is Routing in Laravel 12?

Routing in Laravel maps incoming HTTP requests (URLs) to specific logic such as closures or controller methods. Routes are defined primarily in the routes/ directory.

Route Files in Laravel 12
File Purpose
web.php Web routes (sessions, CSRF, views)
api.php API routes (stateless, JSON)
console.php Artisan commands
channels.php Broadcasting channels


Laravel 12 Routing and Middleware: Complete Guide with Code Snippets

Table Of Content

1 Introduction

Laravel 12 continues Laravel's tradition of clean syntax, developer productivity, and powerful abstractions. Two of the most important concepts every Laravel developer must master are Routing and Middleware. Together, they control how HTTP requests enter your application and how they are filtered, authenticated, or modified before reaching controllers.

If you're upgrading from a previous version, check out our guide on How to Upgrade from Laravel 11 to Laravel 12 Without Breaking Changes before diving in.

This complete guide explains Laravel 12 routing and middleware step by step, with real code examples, best practices, and production-ready patterns.

We'll dive into defining routes, parameter handling, route groups, model binding, rate limiting, middleware creation, registration, groups, parameters, and integration with routing.

2 Setting Up Basic Routes in Laravel 12

Routes in Laravel 12 are defined primarily in the routes directory. The web.php file handles browser-accessible routes with the web middleware group for sessions and CSRF protection, while api.php is for stateless API endpoints.
To define a simple GET route:
    
        use Illuminate\Support\Facades\Route;

        Route::get('/greeting', function () {
            return 'Hello World';
        });
  
    
To define a simple POST route:
    
        use Illuminate\Support\Facades\Route;

       Route::post('/submit', function () {
          return 'Form submitted';
       });
    
Laravel supports all HTTP verbs: GET, POST, PUT, PATCH, DELETE, OPTIONS. For versatility:
Multiple HTTP Methods and Any HTTP Method
    
       Route::match(['get', 'post'], '/', function () {
            // Handles both GET and POST
        });

        Route::any('/', function () {
            // Handles any method
        });
    
Dependency injection is seamless; type-hint services in closures:
    
       use Illuminate\Http\Request;

        Route::get('/users', function (Request $request) {
            // Access request data
        });
    
CSRF protection is automatic for web routes. Include tokens in forms:
    
      <form method="POST" action="/profile">
            @csrf
            ...
      </form>
    
Redirects and views are straightforward:
    
     Route::redirect('/here', '/there', 301); // Permanent redirect

     Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
    
To list routes:
    
        php artisan route:list -v
    
Customization happens in bootstrap/app.php:
    
        ->withRouting(
            web: __DIR__.'/../routes/web.php',
            commands: __DIR__.'/../routes/console.php',
            health: '/up'
        )
    
This setup allows adding custom route files dynamically, enhancing modularity in Laravel 12.

3 Advanced Routing Features

Route parameters capture URL segments:
    
       Route::get('/user/{id}', function (string $id) {
          return 'User ' . $id;
       });
    
Optional parameters use defaults:
    
       Route::get('/user/{name?}', function (?string $name = 'John') {
            return $name;
       });
    
Constrain with regex:
    
      Route::get('/user/{id}', function (string $id) {
            // ...
        })->whereNumber('id');
    
Laravel 12 provides several convenient constraint methods: whereNumber(), whereAlpha(), whereAlphaNumeric(), and whereUuid().

Named routes simplify URL generation:
    
      Route::get('/user/profile', function () {
        // ...
    })->name('profile');

    $url = route('profile', ['id' => 1]);
    
Groups share attributes:
    
        Route::middleware(['auth'])->prefix('admin')->group(function () {
        Route::get('/users', function () {
            // Matches /admin/users with auth middleware
        });
    });
    
Model binding injects Eloquent models:
Route model binding automatically resolves Eloquent models from route parameters, eliminating manual database queries. For more Eloquent techniques, see our Laravel 12 Eloquent Tips and Tricks for Beginners.
    
    use App\Models\User;

    Route::get('/users/{user}', function (User $user) {
        return $user->email;
    });
    
Customize with scopes or custom keys:
    
        Route::get('/posts/{post:slug}', function (Post $post) {
            return $post;
        })->scopeBindings();
    
Rate limiting prevents abuse:
Rate limiting is essential for protecting your application from excessive requests. For more optimization strategies, read our Laravel 12 Performance Optimization Tips.
In AppServiceProvider:
    
        use Illuminate\Cache\RateLimiting\Limit;
        use Illuminate\Support\Facades\RateLimiter;

        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
        });
    
Attach to routes:
    
        Route::middleware('throttle:api')->group(function () {
            // Limited routes
        });
    
Form spoofing for non-POST methods:
    
        @method('PUT')
    
Access current route:
    
        $currentRoute = Route::currentRouteName();
    
These features make routing flexible and powerful, handling complex scenarios with ease.

4 API Routing in Laravel 12

Laravel API routes are defined in routes/api.php. All API routes are automatically prefixed with /api and are stateless (no sessions or CSRF).

For API routes, install Sanctum first:
    
       php artisan install:api
    
This creates api.php and sets up token authentication:
    
       Route::get('/user', function (Request $request) {
        return $request->user();
    })->middleware('auth:sanctum');
    
API Resource Routes
Use apiResource to generate routes without create and edit (forms not needed for APIs):
    
       use App\Http\Controllers\PostController;

       Route::apiResource('posts', PostController::class);
    
API Versioning with Route Prefixes
Organize your API versions using route groups:
    
       Route::prefix('v1')->group(function () {
           Route::apiResource('posts', App\Http\Controllers\Api\V1\PostController::class);
       });

       Route::prefix('v2')->group(function () {
           Route::apiResource('posts', App\Http\Controllers\Api\V2\PostController::class);
       });
    
For a complete walkthrough on building APIs, check our How to Build a REST API in Laravel 12: Step-by-Step Guide.

5 Understanding Middleware in Laravel 12

Middleware acts as a filter layer between the request and the application. It can:
  • Authenticate users
  • Validate tokens
  • Log requests
  • Block access
  • Modify responses
Default Middleware in Laravel 12
Some built-in middleware include:
  • auth — Ensures the user is authenticated
  • guest — Restricts access to unauthenticated users only
  • verified — Checks if the user's email is verified
  • throttle — Limits request rate to prevent abuse
  • signed — Validates signed URLs
For a detailed look at authentication strategies, see Best Authentication Options in Laravel 12.

Creating Custom Middleware in Laravel 12
Create middleware:
    
       php artisan make:middleware EnsureTokenIsValid
    
Define logic:
    
       namespace App\Http\Middleware;

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

        class EnsureTokenIsValid
        {
            public function handle(Request $request, Closure $next): Response
            {
                if ($request->input('token') !== 'my-secret-token') {
                    return redirect('/home');
                }

                return $next($request);
            }
        }
    
After logic example (middleware that runs after the request is handled):
    
      public function handle(Request $request, Closure $next): Response
        {
            $response = $next($request);
            // Modify response headers, log data, etc.
            return $response;
        }
    
The withoutMiddleware() method lets you exclude specific middleware from individual routes, which is useful for testing or public endpoints within protected groups:
    
     Route::get('/profile', function () {
        // ...
    })->withoutMiddleware([EnsureTokenIsValid::class]);
    
This provides flexibility without affecting the global middleware stack.

6 Defining and Registering Middleware

In bootstrap/app.php
    
       use App\Http\Middleware\EnsureTokenIsValid;

        ->withMiddleware(function (Middleware $middleware): void {
            $middleware->append(EnsureTokenIsValid::class);
        });
    
For routes:
    
      Route::get('/profile', function () {
            // ...
        })->middleware(EnsureTokenIsValid::class);
    
Aliases for brevity:
    
      $middleware->alias(['token' => EnsureTokenIsValid::class]);
    
Prioritize order:
    
    $middleware->priority([
        // List classes in order
    ]);
    
Default groups like web and api can be modified:
    
        $middleware->web(append: [CustomMiddleware::class]);
    
These updates in Laravel 12 streamline middleware management, reducing configuration overhead.

7 Middleware Groups and Parameters

Groups bundle middleware:
    
      $middleware->group('admin', [
        Authenticate::class,
        Authorize::class,
    ]);
    
Assign:
    
     Route::middleware('admin')->group(function () {
        // ...
    });
    
Parameters pass data:
    
      public function handle(Request $request, Closure $next, string $role): Response
        {
            if ($request->user()->role !== $role) {
                abort(403, 'Unauthorized');
            }
            return $next($request);
        }

        Route::middleware('role:admin')->get('/', function () {
            // Only accessible by admin role
        });
    
Terminable middleware runs post-response (requires FastCGI). This is useful for logging, analytics, or cleanup tasks that don't need to delay the response:
    
    public function terminate(Request $request, Response $response): void
    {
        // Log request/response after it's sent to the browser
    }
    
For heavy post-response tasks, consider using Laravel 12 Queues and Jobs instead of terminable middleware.

Register as singleton for shared instances across the request lifecycle.

8 Integrating Middleware with Routing

Middleware integrates seamlessly with routes. For resource controllers:
    
      Route::resource('photos', PhotoController::class)->middleware('auth');
    
To apply middleware to only specific resource methods, use only() or except() combined with separate route definitions:
    
     // Public routes (no auth)
     Route::resource('photos', PhotoController::class)
        ->only(['index', 'show']);

     // Protected routes (with auth)
     Route::resource('photos', PhotoController::class)
        ->only(['create', 'store', 'edit', 'update', 'destroy'])
        ->middleware('auth');
    
You can also exclude middleware on specific routes within a group using withoutMiddleware():
    
     Route::middleware('auth')->group(function () {
        Route::get('/dashboard', [DashboardController::class, 'index']);
        
        // This route skips auth within the protected group
        Route::get('/public-stats', [StatsController::class, 'index'])
            ->withoutMiddleware('auth');
     });
    
Rate limiting middleware ties into routing for API protection. Combined with route groups and named rate limiters, you can build granular access control for different parts of your application.
Continue Learning Laravel 12
Now that you understand routing and middleware, explore more Laravel 12 topics to level up your skills:

9 Conclusion

Laravel 12 routing and middleware provide a robust foundation for building secure, scalable, and maintainable web applications. Mastering these concepts allows you to control request flow, protect resources, and keep your application clean and professional.

Key Takeaways:
  • Define routes in web.php for browser routes and api.php for stateless API endpoints
  • Use route groups, named routes, and model binding to keep route files clean
  • Register and manage middleware centrally in bootstrap/app.php
  • Apply rate limiting to protect APIs from abuse
  • Use terminable middleware or queues for post-response processing
Whether you're building REST APIs, admin panels, or SaaS platforms, routing and middleware are essential tools in your Laravel toolkit.

If you run into issues while implementing these patterns, our guide on Common Laravel 12 Errors and How to Fix Them can help you troubleshoot quickly.
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

Routing is now configured via the bootstrap/app.php file using a fluent API, allowing more flexibility.

Use Route::get('/path', function() { ... }); in routes/web.php.

They allow passing additional data to middleware, like roles in authentication checks.

Define limiters in AppServiceProvider and attach via throttle middleware.

Laravel 12 centralizes middleware registration in bootstrap/app.php using a fluent API. You can use withoutMiddleware() to exclude middleware on specific routes and manage middleware groups, aliases, and priority all from one location.

Use {param?} in the route definition with a default value in the closure.

It automatically injects Eloquent models based on route parameters.

Use the group() method in bootstrap/app.php to bundle middleware.

Yes, using terminable middleware with a terminate() method.

Run php artisan route:list in the terminal.

web.php routes use the web middleware group which includes session handling, CSRF protection, and cookie encryption. api.php routes are stateless, prefixed with /api, and designed for token-based authentication using Laravel Sanctum.

Use the only() or except() methods to split your resource routes, then apply middleware to the protected group. For example: Route::resource("photos", PhotoController::class)->only(["create", "store"])->middleware("auth");