Laravel Routing: Named Routes, Route Groups & Model Binding
Laravel provides powerful routing features that make your applications clean, readable, and flexible. In this tutorial, we’ll cover Named Routes, Route Groups, and Route Model Binding (implicit, explicit, and customized).
Named Routes
Named routes let you generate URLs and redirects using route names instead of hardcoding paths.
Defining a Named Route
Route::get('/user/profile', function () {
return 'User Profile';
})->name('profile');
Or for controllers:
Route::get('/user/profile', [UserProfileController::class, 'show'])->name('profile');
Route names must be unique.
Generating URLs & Redirects
$url = route('profile'); // Generate URL
return redirect()->route('profile'); // Redirect
return to_route('profile'); // Shortcut redirect
With Parameters
Route::get('/user/{id}/profile', fn($id) => "User $id")->name('profile');
$url = route('profile', ['id' => 1]);
// /user/1/profile
Extra values become query strings:
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// /user/1/profile?photos=yes
Inspecting the Current Route
You can check the current route name in middleware or controllers:
public function handle(Request $request, Closure $next)
{
if ($request->route()->named('profile')) {
// Perform action if "profile" route
}
return $next($request);
}
Route Groups
Route groups let you share attributes (middleware, prefix, name, etc.) across multiple routes.
Middleware for Groups
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', fn() => 'Dashboard');
Route::get('/settings', fn() => 'Settings');
});
Controller Groups
use App\Http\Controllers\OrderController;
Route::controller(OrderController::class)->group(function () {
Route::get('/orders/{id}', 'show');
Route::post('/orders', 'store');
});
Subdomain Routing
Route::domain('{account}.example.com')->group(function () {
Route::get('/user/{id}', fn($account, $id) => "Account: $account, User: $id");
});
Route Prefix
Route::prefix('admin')->group(function () {
Route::get('/users', fn() => 'Admin Users');
});
// URL: /admin/users
Route Name Prefix
Route::name('admin.')->group(function () {
Route::get('/users', fn() => 'Users')->name('users');
});
// Route name = admin.users
Route Model Binding
Instead of fetching models manually, Laravel can inject models directly into routes.
Implicit Binding
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
});
{user}matches the$uservariable.- If no user is found →
404.
In Controllers
Route::get('/users/{user}', [UserController::class, 'show']);
public function show(User $user) {
return view('user.profile', compact('user'));
}
Soft Deleted Models
Allow binding of trashed models:
Route::get('/users/{user}', fn(User $user) => $user)->withTrashed();
Customizing the Key
Use a column other than id:
Route::get('/posts/{post:slug}', fn(Post $post) => $post);
Or override in model:
public function getRouteKeyName(): string {
return 'slug';
}
Scoped Bindings
Bind nested resources automatically:
Route::get('/users/{user}/posts/{post:slug}', fn(User $user, Post $post) => $post);
- Laravel assumes
Userhas apostsrelationship.
Enable globally:
Route::scopeBindings()->group(function () {
Route::get('/users/{user}/posts/{post}', fn(User $u, Post $p) => $p);
});
Disable with:
->withoutScopedBindings()
Handling Missing Models
Route::get('/locations/{location:slug}', [LocationsController::class, 'show'])
->name('locations.view')
->missing(fn(Request $r) => Redirect::route('locations.index'));
Enum Binding
Use PHP 8.1 Enums in routes:
enum Category: string {
case Fruits = 'fruits';
case People = 'people';
}
Route::get('/categories/{category}', fn(Category $category) => $category->value);
- Works only if value matches enum, else →
404.
Explicit Model Binding
Define model binding manually in AppServiceProvider:
use App\Models\User;
public function boot(): void {
Route::model('user', User::class);
}
Now:
Route::get('/users/{user}', fn(User $user) => $user);
Custom Resolution Logic
Route::bind('user', function ($value) {
return User::where('name', $value)->firstOrFail();
});
Or inside the model:
public function resolveRouteBinding($value, $field = null) {
return $this->where('name', $value)->firstOrFail();
}
For child models:
public function resolveChildRouteBinding($childType, $value, $field) {
return parent::resolveChildRouteBinding($childType, $value, $field);
}
Important
- Named Routes → Generate URLs/redirects easily with
route()andredirect()->route(). - Route Groups → Share middleware, prefixes, controllers, and domains.
- Route Model Binding → Automatically inject models (implicit, explicit, or customized).
- Supports soft deletes, custom keys, enums, scoped bindings, and custom missing behavior.
