Routing Basics
A route is simply a mapping between a URL and the code that should run when a request hits that URL. Laravel's routing layer is deliberately expressive — most routes read almost like plain English — while still supporting everything a real application needs: parameters, constraints, naming, and more. This page covers the fundamentals; the next lesson builds on it with groups, resource routes, and model binding.
1. web.php vs api.php
Every new project ships with routes/web.php already wired up for browser-facing routes —
these automatically get session state, cookie encryption, and CSRF protection applied via Laravel's
default web middleware group. If you also work with routes/api.php, know that it's built
for stateless routes instead: no sessions or CSRF, every route prefixed with /api
automatically, and typically meant to be consumed by a JavaScript frontend or an external client rather
than a browser navigating directly. This tutorial track focuses on web.php, since that's
where the large majority of a typical application's routes live.
2. The HTTP Verb Methods
Routes are registered against the Route facade, with one method per HTTP verb:
| Method | Typical use |
|---|---|
Route::get() | Retrieving a page or resource — the vast majority of routes in a typical app |
Route::post() | Submitting a form or creating a new resource |
Route::put() | Replacing an existing resource entirely |
Route::patch() | Partially updating an existing resource |
Route::delete() | Deleting a resource |
3. Closures vs Controllers
The simplest possible route returns a response directly from a closure — handy for quick tests or genuinely trivial pages:
<?php
// routes/web.php
Route::get('/', function () {
return view('welcome');
});
For anything beyond a trivial page, point the route at a controller method instead, using the
[Controller::class, 'method'] array syntax:
Route::get('/users', [UserController::class, 'index']);
Controllers are covered in full later in this track, but in short: this tells Laravel "when someone
requests GET /users, instantiate UserController and call its
index() method."
4. Route Parameters
Segments of the URL can be captured as parameters by wrapping a name in curly braces. Laravel passes the matched value into your closure or controller method automatically:
Route::get('/users/{id}', function ($id) {
return "User #" . $id;
});
A parameter can be made optional by appending a ? — in that case, give the matching
function argument a default value too, since the parameter may not be present at all:
Route::get('/users/{id?}', function ($id = null) {
return $id ? "User #" . $id : "No user specified";
});
5. Constraining Parameters with where()
By default a route parameter matches almost any character. Use where() to restrict it with
a regular expression — useful for making sure, say, an {id} segment only ever matches
digits:
Route::get('/users/{id}', [UserController::class, 'show'])
->where('id', '[0-9]+');
6. Naming Routes and the route() Helper
Giving a route a name lets you refer to it consistently everywhere else in your application — in Blade
views, redirects, and elsewhere — without ever hardcoding its literal URL. If the URL ever changes,
every reference built with the route() helper keeps working automatically:
Route::get('/users/{id}', [UserController::class, 'show'])
->name('users.show');
// building a URL to that route elsewhere in the app
$url = route('users.show', ['id' => 5]);
// => /users/5
users.show, users.index, articles.edit — this reads naturally and avoids naming collisions as an app grows.7. Listing All Registered Routes
Once a project has more than a handful of routes, it's easy to lose track of what's registered. Artisan can print every route Laravel currently knows about, straight from the terminal:
php artisan route:list
The output shows each route's HTTP verb, URI, name (if any), and the controller/action or closure it points to — an invaluable debugging tool when a request isn't reaching the code you expect.