Laravel 13 tutorial #2: routing, parameters and model binding
verified on 7 September 2026 · 5 min
Routes are declared in routes/web.php with Route::get('/chemin', [MonController::class, 'methode']). Name them with ->name() to build your links with route('nom') rather than hard-coding them. The string syntax 'Controller@methode' has not worked since Laravel 8.
A route ties an address to some code. It is the entry point of every request: Laravel reads the requested URL, looks for the route that matches and runs whatever it points at. This chapter goes through the four shapes that link can take.
The simplest route
Every route of the public site is declared in routes/web.php. Here is what the file holds right after installation:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});That route says: when someone requests / with GET, return the welcome view, that is the resources/views/welcome.blade.php file.
Route::get() takes two arguments: the address, and what to do with it. That second argument can take several forms.
Returning a string
Route::get('/bonjour', function () {
return 'Bonjour !';
});Visit http://127.0.0.1:8000/bonjour: the browser prints the raw text. Handy to confirm a route is reached, rarely useful beyond that.
Returning a view
To check that welcome really is the view shown on the home page, open resources/views/welcome.blade.php and add a visible line anywhere inside the <body>:
<h1>Bonjour tout le monde !</h1>Reload the home page: the heading shows up. You have just changed a view without touching the route.
Calling a controller
In a real project the logic does not live in the routes file but in a controller. The route then only names a class and a method:
use App\Http\Controllers\PostController;
Route::get('/article', [PostController::class, 'show']);The [PostController::class, 'show'] array means “call the show method of the PostController class”. The controller does not exist yet: the next chapter creates it. Note the use at the top of the file, which imports the class. Without it, PHP looks for PostController in the global namespace and never finds it.
Plenty of tutorials written for Laravel 7 or earlier use Route::get('/article', 'PostController@show'). The automatic namespace prefix that made this form work was removed in Laravel 8. On Laravel 13 it fails with this message:
Illuminate\Contracts\Container\BindingResolutionException
Target class [PostController] does not exist.Laravel looks for the class at the root of the namespace instead of App\Http\Controllers. Always use the array form.
URL parameters
A blog needs variable addresses: /article/mon-premier-article, /article/un-autre. The part that changes becomes a parameter, written between braces:
Route::get('/article/{slug}', function (string $slug) {
return "Vous avez demandé l'article : {$slug}";
});Laravel captures everything after /article/ and passes it to the function under the name $slug. The parameter name in the URL and the argument name have to match.
You can constrain the shape you expect. Here the route only answers if the identifier is numeric:
Route::get('/article/{id}', function (int $id) {
return "Article numéro {$id}";
})->whereNumber('id');A URL such as /article/bonjour then returns a 404 instead of reaching your code with an unexpected value.
Named routes
Hard-coding URLs in your templates is fragile: the day you rename /article/ to /blog/, you have to track down every link. Naming the route settles it:
Route::get('/article/{slug}', [PostController::class, 'show'])->name('post');The link is then built from the name, never from the address:
route('post', ['slug' => 'mon-premier-article'])
// http://127.0.0.1:8000/article/mon-premier-articleIn a Blade view, it reads:
<a href="http://%20route('post',%20$post)%20">{{ $post->title }}</a>Change the address in web.php and every link follows. That is how this tutorial builds all its links from chapter 7 onwards.
Route model binding
Laravel can go one step further. If the parameter carries the name of a model, the framework fetches the record itself:
use App\Models\Post;
Route::get('/article/{post}', function (Post $post) {
return $post->title;
});Laravel reads the URL segment, queries the posts table and returns a 404 on its own if nothing matches. You get the object straight away, without writing the query. By default the lookup uses the id column; chapter 6 shows how to make it use the slug instead.
Route model binding removes half of the code a controller usually carries. It is used everywhere in the rest of the tutorial.
The other HTTP verbs
Route::get() answers read requests. For forms and APIs, Laravel exposes the other methods:
Route::post('/article', [PostController::class, 'store']);
Route::put('/article/{post}', [PostController::class, 'update']);
Route::delete('/article/{post}', [PostController::class, 'destroy']);This tutorial only uses get: writes go through the admin panel installed in chapter 4.
Listing every route
This command lists what your application knows how to serve:
php artisan route:list --except-vendorOn the finished project of this tutorial, once the chapter 4 admin panel is installed, it also lists the back-office routes: they are declared by classes in your app/Filament folder, not by the package itself. To see only the site pages, add --except-path=admin:
php artisan route:list --except-vendor --except-path=admin GET|HEAD / .................................... home › IndexController
GET|HEAD article/{post} ................... post › PostController@show
GET|HEAD categorie/{category} .......... category › CategoryController
GET|HEAD etiquette/{tag} ......................... tag › TagController
GET|HEAD recherche .................... search › PostController@searchThe --except-vendor option hides routes added by installed packages, --except-path=admin leaves out those of the admin panel, which really are yours. It is the first command to run when an address returns a 404 although you thought you had declared it.
The next chapter creates the controllers and the views these routes point at.