Laravel Tutorial · Laravel Basics · Lesson 4 of 27
Route Parameters and Model Binding
Capture parts of the URL, make them optional, constrain them with patterns, and let Laravel load Eloquent models from IDs automatically.
Required and optional parameters
Wrap a URL segment in braces to capture it: /posts/{id}. Add ? and a default value for optional ones: /greet/{name?}.
Constraints reject values that don't match a pattern: ->whereNumber('id'), ->whereAlpha('name'), ->where('slug', '[a-z0-9-]+'). A request that doesn't match gets a 404 instead of reaching your code.
<?php
use Illuminate\Support\Facades\Route;
Route::get('/posts/{id}', fn (int $id) => "Post #$id")->whereNumber('id');
Route::get('/greet/{name?}', fn (string $name = 'stranger') => "Hello, $name!");
Route::get('/tags/{tag}', fn (string $tag) => "Tag: $tag")->where('tag', '[a-z0-9-]+');
visit('GET', '/posts/15');
visit('GET', '/posts/abc'); // fails the number constraint: 404
visit('GET', '/greet');
visit('GET', '/greet/Ana');
visit('GET', '/tags/laravel-13');
Output
GET /posts/15 -> 200 Post #15
GET /posts/abc -> 404 {
"message": "The route posts/abc could not be found."
}
GET /greet -> 200 Hello, stranger!
GET /greet/Ana -> 200 Hello, Ana!
GET /tags/laravel-13 -> 200 Tag: laravel-13Run this on your computer — see “Get Started” for setup.
Route model binding
If a parameter is type-hinted with an Eloquent model, Laravel looks it up for you: /posts/{post} with Post $post runs Post::findOrFail($id). A missing record becomes a 404 automatically. Use {post:slug} to look up by another column.
<?php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Schema;
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('slug')->unique();
$table->string('title');
});
class Post extends Model
{
public $timestamps = false;
protected $guarded = [];
}
Post::create(['slug' => 'hello-laravel', 'title' => 'Hello Laravel']);
Route::get('/posts/{post}', fn (Post $post) => $post); // looked up by id
Route::get('/blog/{post:slug}', fn (Post $post) => $post->title); // looked up by slug
visit('GET', '/posts/1');
visit('GET', '/blog/hello-laravel');
visit('GET', '/blog/missing');
Output
GET /posts/1 -> 200 {"id":1,"slug":"hello-laravel","title":"Hello Laravel"}
GET /blog/hello-laravel -> 200 Hello Laravel
GET /blog/missing -> 404 {
"message": "No query results for model [Post] missing"
}Run this on your computer — see “Get Started” for setup.
Test yourself
What happens when a route-model-bound record doesn't exist?
The parameter is nullLaravel returns a 404 responseA 500 errorAn empty model is created
Show answer
Answer: Laravel returns a 404 response