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 |

Table Of Content
1 Introduction
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
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::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
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 RoutesUse 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 PrefixesOrganize 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
- Authenticate users
- Validate tokens
- Log requests
- Block access
- Modify responses
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
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
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
$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
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. Related Laravel 12 Guides
Now that you understand routing and middleware, explore more Laravel 12 topics to level up your skills:
- How to Build a REST API in Laravel 12: Step-by-Step Guide with Examples — Apply your routing knowledge to build a complete API
- Best Authentication Options in Laravel 12 Using WorkOS AuthKit — Secure your routes with modern authentication
- Laravel 12 Queue and Jobs Tutorial: Background Processing Made Easy — Offload heavy tasks from middleware to queues
- Laravel 12 Eloquent Tips and Tricks for Beginners — Master the ORM behind route model binding
- Laravel 12 Performance Optimization Tips — Optimize route caching and middleware execution
- Common Laravel 12 Errors and How to Fix Them Quickly — Troubleshoot routing and middleware issues
9 Conclusion
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
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.
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");
