Laravel Routing: Basic Routes, Parameters & Groups | TutorialDev

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, theyll see “Hello, Tom!”.
If they visit just /user/, theyll 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

});

Laravel Route Groups

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;

});

Laravle Route Parameters

 

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 Laravels 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.

Laravle Subdomain Routing

 

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.

 

Laravel Naming Route Groups

 

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 isnt 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 doesnt exist, it redirects to the locations 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, theyll 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 !