Picture a large map with many various places indicated on it. Laravel routing is similar to an exclusive GPS system that guides you to the precise location you wish to travel to on this map. When you enter a website address in your browser, Laravel’s routing mechanism determines what portion of the site to display to you. It’s like telling your friend how to meet you at the park – you give them directions, and they will know exactly where to go!
Laravel’s Routing is one of the most crucial parts of any web application. It recount how your application responds to the user’s requests. In Laravel, routes define how different URLs (like yourwebsite.com/home) should function and what data they should return.
Basic Routing in Laravel
At the basic point , a route in Laravel connects a URL to a function. Here we can give some simple example:
use Illuminate\Support\Facades\Route; Route::get('/hello', function () { return 'Hello World'; });
- When a user visits yourwebsite.com/hello, the function will return “Hello World”. where yourwebsite.com is your localhost:8000. For general purpose we use domain name not localhost.
- The Route::get() method defines a route that responds to a GET request.
Where Do Routes Live?
Laravel stock the routes in specific files inside the routes folder. Most of the common ones are:
- web.php → For routes which are load in a browser (e.g., user-facing pages).
- api.php → For routes which are used by APIs (e.g., mobile apps, third-party services). For latest laravel 12.x or Laravel 11 api.php is removed.
Example can be set as, if you define this route in web.php:
use App\Http\Controllers\UserController; Route::get('/user', [UserController::class, 'index']);
When someone visits yourwebsite.com/user, Laravel will execute the index method inside UserController.
Classification of Routes:
Laravel permits one to define routes for different types of HTTP requests:
Route::get('/users', function () {}); // For retrieving the data
Route::post('/users', function () {}); // For submitting the new data
Route::put('/users/{id}', function ($id) {}); // For updating the existing data
Route::delete('/users/{id}', function ($id) {}); // For deleting the data
One can also define routes which response to multiple request types:
Route:: can match(['get', 'post'], '/contact', function () { return 'Contact Page'; });
This type of route is not so common in your real world project. But we need to learn it.
Route::any('/any', function () { return 'This works for any HTTP method!'; });
Using Route Parameters
Sometimes, one need to pass values through the URL, like yourwebsite.com/user/5. It is called a route parameter.
Laravel Route Parameters Examples
Route::get('/user/{id}', function ($id) { return "User ID: $id"; });
- {id} is a placeholder that gets replaced with orginal values (e.g., 5).
- If someone visits /user/5, Laravel will return: “User ID: 5”.
One can also make the parameters optional:
Route::get('/user/{name?}', function ($name = 'Guest') { return "Hello, $name!"; });
If the user visits /user/Tom, they’ll see “Hello, Tom!”.
If they visit just /user/, they’ll see “Hello, Guest!”.
Laravel Named Route Usage
The Named routes makes it easier to refer routes in the application:
Route::get('/dashboard', function () { return 'Welcome to Dashboard'; })->name('dashboard');
Now, one can generate the URL for this route anywhere in the code using:
$url = route(‘dashboard’);
Route Groups
Instead of adding the same settings to multiple routes, one can group them:
1. Using Middleware
Route::middleware(['auth'])->group(function () { Route::get('/profile', function () {}); Route::get('/settings', function () {}); });
Now, both /profile and /settings required user’s authentication.
2. Using Prefixes
While using prefixes if all routes in a group share a common URL prefix:
Route::prefix('admin')->group(function () { Route::get('/dashboard', function () {}); // URL: /admin/dashboard Route::get('/users', function () {}); // URL: /admin/users });
Redirect & View Routes
1. Redirect Routes
If you want to automatically send users from one page to another:
Route::redirect('/old-page', '/new-page');
2. View Routes
If a route only returns a view, then you need not want a controller:
Route::view('/welcome', 'welcome', ['name' => 'John']);
This will show the welcome.blade.php file and pass name = John to it.
Route Caching (For Speed)
If the app has various routes, you can improve performance using caching:
php artisan route:cache
This combines all routes into a faster format. If one include new routes, clear the cache:
php artisan route:clear
Listing All Routes
To see a list of all routes in the Laravel app, run:
php artisan route:list
This shows all defined routes, their URLs, and assigned controllers.
Customizing Routes in Laravel
Inevitably , Laravel loads its routes from a few predefined files placed in the routes folder. These include:
- web.php – Handles web routes (the ones used in browsers).
- api.php – Handles API-related routes.
- console.php – Used for defining Artisan commands.
Laravel loads these routes in the bootstrap/app.php file as this:
use Illuminate\Foundation\Application; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', )->create();
But sometimes, one might include a new route file for specific routes. An example can be set at this point, if one wants to separate webhook-related routes, you can add them like this:
use the Illuminate\Support\Facades\Route; ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', then: function () { Route::middleware('api') ->prefix('webhooks') ->name('webhooks.') ->group(base_path('routes/webhooks.php')); }, )
Complete Control Over Routes
If one wants to completely control either which routes are loaded and disable Laravel’s automatic loading, one can do this:
use Illuminate\Support\Facades\Route; ->withRouting( commands: __DIR__.'/../routes/console.php', using: function () { Route::middleware('api') ->prefix('api') ->group(base_path('routes/api.php')); Route::middleware('web') ->group(base_path('routes/web.php')); }, )
At this point , if you’re telling Laravel, “I’ll handle route loading myself.” It means no default HTTP routes will be loaded unless you bluntly define them.
Route Parameters
Either , one needs to capture dynamic values from the URL. This act is done using route parameters.
Required Route Parameters
If someone wants to capture a user ID from the URL, you can do:
Route::get(‘/user/{id}’, function (string $id) {
return ‘User ‘ . $id;
});
For having multiple parameters:
Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) { return "Post ID: $postId, Comment ID: $commentId"; });
- Parameters go inside {}.
- They are automatically passed to the function in the order they appear in the URL.
Using Dependency Injection
If anyone needs access to Laravel’s built-in request handling, so he can inject it into your route like this:
use Illuminate\Http\Request; Route::get('/user/{id}', function (Request $request, string $id) { return 'User ' . $id; });
This lets you use $request inside the function to get additional details about the request.
Optional Route Parameters
Sometimes, a parameter may not always exist. So, one can make it optional by adding ? and setting a default value.
Route::get('/user/{name?}', function (?string $name = 'Guest') { return $name; });
- Whether the name parameter is provided, it will return the value.
- If not, it will default to “Guest”.
Restricting Route Parameters Using Regular Expressions
Many times, we want to limit what kind of data a parameter can accept.
Using the where() Method
You can ensure a parameter only accepts specific formats while using regular expressions.
Route::get('/user/{name}', function (string $name) { return "Hello, $name"; })->where('name', '[A-Za-z]+'); // Only allows letters
Route::get('/user/{id}', function (string $id) { return "User ID: $id"; })->where('id', '[0-9]+'); // Only allows numbers
We can also apply multiple constraints:
Route::get('/user/{id}/{name}', function (string $id, string $name) { return "User ID: $id, Name: $name"; })->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
Shortcut Methods for Common Constraints
Laravel provides helper methods to make this process easier:
Route::get('/user/{id}', function (string $id) { return "User ID: $id"; })->whereNumber('id'); // Only numbers
Route::get('/user/{name}', function (string $name) { return "Hello, $name"; })->whereAlpha('name'); // Only letters
Route::get('/user/{id}', function (string $id) { return "User ID: $id"; })->whereUuid('id'); // Only valid UUIDs
Route::get('/category/{category}', function (string $category) { return "Category: $category"; })->whereIn('category', ['movie', 'song', 'painting']); // Restricts to a list of values
If a request doesn’t match with the defined pattern, Laravel automatically returns to a 404 error.
Global Route Constraints
you can set global constraints in AppServiceProvider.php.
use the Illuminate\Support\Facades\Route; public function boot(): void { Route::pattern('id', '[0-9]+'); // Ensures 'id' is always numeric }
Now, any route using {id} will automatically enforce this rule.
Route::get('/user/{id}', function (string $id) { return "User ID: $id"; // Only works if {id} is a number in itself });
Allowing Forward Slashes in Parameters
As an automatic consequence Laravel does not allow / inside route parameters. So,if you need to allow it, you must use .* in the where() method.
Route::get('/search/{query}', function (string $query) { return "Search results for: $query"; })->where('query', '.*');
However, this only works for the last segment of the route.
What Are Named Routes?
Named routes gives a name to a route so one can easily refer it later. Inspite of writing out the full URL, just use the name you assigned.
How to Name a Route
An example is given below to name a route:
Route::get('/user/profile', function () { return 'User Profile'; })->name('profile');
Whenever one needs to generate a URL for this route, he can do:
$url = route('profile'); // Outputs: /user/profile
And if soomeone needs to redirect this route, he can use:
return redirect()->route('profile');
Named Routes for Controller Actions
If one is using controllers, he can still name his routes like this:
Route::get('/user/profile', [UserProfileController::class, 'show'])->name('profile');
Routes with Parameters
If the route has a dynamic parameter, such as user ID, then one can pass it when generating the URL:
Route::get('/user/{id}/profile', function ($id) { return "User ID: $id"; })->name('profile');
To generate a URL with a parameter:
$url = route('profile', ['id' => 1]); // Outputs: /user/1/profile
If one needs to include extra query parameters, just pass them in the array:
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// Outputs: /user/1/profile?photos=yes
Checking the Current Route Name
While checking whether the current request is on a specific route, one can do:
if (request()->route()->named('profile')) { // Do something... }
Route Groups
Often,if one have multiple routes that share common characteristics, as using the same middleware, controller, or prefix. Instead of repeating himself, he can group them together.
Grouping with Middleware
If someone wants certain middleware (like authentication) to apply to multiple routes, group them:
Route::middleware(['auth'])->group(function () { Route::get('/dashboard', function () { return 'Dashboard'; }); Route::get('/settings', function () { return 'Settings'; }); }); // Both, now /dashboard and /settings require authentication.
Grouping with a Controller
Either multiple routes belong to the same controller, one can define them like this as shown below:
Route::controller(OrderController::class)->group(function () { Route::get('/orders/{id}', 'show'); Route::post('/orders', 'store'); });
It means:
- GET /orders/{id} will call show() method in OrderController
- POST /orders will call store() method in OrderController
Subdomain Routing
If one’s application has subdomains, he can tackle them same as this:
Route::domain('{account}.example.com')->group(function () { Route::get('/user/{id}', function ($account, $id) { return "User $id in account $account"; }); }); // In this section , {account} will capture the subdomain part dynamically.
Adding a URL Prefix to Routes
You can add a prefix to all routes in a group using prefix():
Route::prefix('admin')->group(function () { Route::get('/users', function () { return 'Admin Users'; }); });
So,this route will be available at /admin/users.
Naming Route Groups
If someone wants to include a prefix to route names, use name():
Route::name('admin.')->group(function () { Route::get('/users', function () { return 'Admin Users'; })->name('users'); });
Naturally , the route name will be admin.users instead of just users.
Route Model Binding
Whenever a route includes a model ID, one specifically fetch the model from the database. Laravel can automatically do this for you!
Implicit Model Binding
Instead of manually doing this :
Route::get('/users/{id}', function ($id) { $user = User::findOrFail($id); return $user->email; });
You can let Laravel do it for you:
use App\Models\User; Route::get('/users/{user}', function (User $user) { return $user->email; });
Laravel automatically fetches the User model using the provided ID. If no user is found, it returns a 404 error automatically.
Soft Deleted Models
Laravel ignores soft-deleted records, while using implicit binding. If someone wants to include them, use withTrashed():
Route::get(‘/users/{user}’, function (User $user) {
return $user->email;
})->withTrashed();
Using a Column Other Than ID
If one wants to get models by slug instead of ID, do this:
Route::get('/posts/{post:slug}', function (Post $post) { return $post; });
By making this the default behavior for a model, update the model like this:
public function getRouteKeyName(): string { return 'slug'; }
So, Laravel will always bring Post models using the slug instead of the ID.
Scoped Bindings
If a model is placed inside another (e.g., a post belongs to a user), Laravel assures the post belongs to the given user:
Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) { return $post; });
Laravel automatically checks if the Post belongs to the given User or not.
If one wants this behavior for multiple routes, one can enable it for a group also:
Route::scopeBindings()->group(function () { Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) { return $post; }); });
Handling Missing Models
When a model isn’t found, Laravel returns a 404 error. But you can customize this:
Route::get('/locations/{location:slug}', [LocationsController::class, 'show']) ->missing(function () { return redirect()->route('locations.index'); });
Whenever a location doesn’t exist, it redirects to the location’s index page instead of showing a 404 error.
Implicit Enum Binding
Laravel enables to use Enums (introduced in PHP 8.1) in one’s routes. When one specify an Enum in a route, Laravel will naturally validate it and return a 404 error if the provided value is not valid.
Example
Suppose one have an Enum called Category with two values:
namespace App\Enums; enum Category: string { case Fruits = 'fruits'; case People = 'people'; }
So, one can define a route like this:
use App\Enums\Category; use Illuminate\Support\Facades\Route; Route::get('/categories/{category}', function (Category $category) { return $category->value; });
Whether someone visits /categories/fruits or /categories/people, it works fine. But if they try /categories/unknown, they’ll get a 404 error naturally.
Explicit Model Binding
Instead of getting models manually from the database in every route, Laravel lets you bind route parameters to models.
Example
You can also register a model binding in AppServiceProvider.php:
use App\Models\User; use the Illuminate\Support\Facades\Route; public function boot(): void { Route::model('user', User::class); }
Presently , in your routes file:
use App\Models\User; Route::get('/users/{user}', function (User $user) { return $user; });
If a user with that ID exists, instantly Laravel will inject the User model . If not, a 404 error is returned.
Customizing Model Binding Logic
Though you want to bring a user by name instead of ID? You can do this:
use App\Models\User; use Illuminate\Support\Facades\Route; public function boot(): void { Route::bind('user', function ($value) { return User::where('name', $value)->firstOrFail(); }); }
For the time being , when a user visits /users/JohnDoe, Laravel will find John Doe by name instead of ID.
Fallback Routes
When no route matches a request, you can define a fallback route:
Route::fallback(function () { return response()->json(['message' => 'Page not found'], 404); });
So, instead of a generic 404 page, you can customize the response.
Rate Limiting
By preventing excessive requests, Laravel allows you to set rate limits.
For example
In AppServiceProvider.php, define a rate limiter:
use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; use Illuminate\Support\Facades\RateLimiter; protected function boot(): void { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->ip()); }); }
This act allows 60 requests per minute per IP.
So, apply this to a route:
Route::middleware(['throttle:api'])->get('/data', function () { return 'Throttled route'; });
Whether a user exceeds the limit during this process, Laravel will automatically return a 429 error (Too Many Requests).
Form Method Spoofing
HTML forms only support GET and POST, but Laravel fetches a way to send PUT, PATCH, or DELETE requests.
An example can be given:
Instead of:
<form action="/update" method="PUT"> You should do: <form action="/update" method="POST"> <input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> </form>
Or, using Blade syntax:
<form action="/update" method="POST"> @method('PUT') @csrf </form>
Accessing the Current Route
Once in a way, you need to check which route is currently being accessed. Laravel uses the helper methods for this:
use Illuminate\Support\Facades\Route; $currentRoute = Route::current(); // Get the current route object $routeName = Route::currentRouteName(); // Get the route name $routeAction = Route::currentRouteAction(); // Get the route action
Cross-Origin Resource Sharing (CORS)
While building an API that serves data to different parts, one needs CORS settings. Laravel manages this automatically but allows customization.
Publishing the CORS config file, run:
php artisan config:publish cors
Then, you can modify the config/cors.php file as needed.
Read More Article
Laravel 12.x Configuration Guide (Simplified)
Understanding Laravel’s Directory Structure in Simple Terms With Easy Steps
How to Install Laravel on your PC, Mac and Linux
Route Caching
When prolonging your Laravel app, caching routes can speed up performance.
Run the command to cache routes:
php artisan route:cache
While changinhg your routes, clear the cache first:
php artisan route:clear
This assures Laravel to register your new routes.
To conclude it can be said that,Laravel routing is flexible and powerful. Mastering these concepts will help one to build efficient and secure applications over times !