Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

Registering Routes in a Laravel Package

When you add HTTP endpoints to a Laravel package, the package must register its routes without relying on the host application's file locations or middleware settings. Middleware is code that runs as Laravel handles a request, before or after the route handler. A route connects a URL and HTTP method to the code that handles a request.

In the package's service provider, load its route file using a path relative to the provider. Then set any shared URL prefix, middleware, and route-name prefix explicitly. A URL prefix adds a segment to each route's URL. A route-name prefix adds text to route names, making them less likely to conflict with names in the host application. The examples below show how to set these options and explain them to package users.

Load a package-owned route file

Laravel's package guide shows how to call loadRoutesFrom() in a service provider's boot() method. The method loads the route file when routes are not cached. Point it to the file included with the package, not to a path inside the host application. Laravel's package documentation uses __DIR__ to build this path, and the service provider implementation shows how Laravel checks whether routes are cached.

prefix('tools')
            ->name('acme-tools.')
            ->group(function (): void {
                $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
            });
    }
}

Here, __DIR__ refers to the directory containing the provider file. The path therefore follows the package’s own layout even when an application installs the package in a different location. A path such as base_path('routes/web.php') points into the host application and is inappropriate when the route file belongs to the package.

The group applies the same settings to every route loaded from the file. The tools prefix changes each route’s URL, and acme-tools. is added to each route name. The name prefix ends with a period, so names such as acme-tools.dashboard read naturally. Laravel explains these group settings in its routing documentation.

Set middleware and controllers explicitly

Naming a package route file web.php does not automatically apply the host application's web middleware to its routes. loadRoutesFrom() loads the file but does not add middleware or a URL prefix. Choose the middleware the package needs, then apply it through a route group or to individual routes.

For example, routes that use browser sessions may need the web middleware group. An API-oriented package may need different middleware. Choose a default based on the package’s behavior, then document how users can change it.

Keep package controllers separate from the host application’s controller namespace. Import the package controller class directly in the route file:

name('dashboard');

The PHP namespace identifies the controller class, while the route-name prefix identifies a route name. They serve different purposes, so a name prefix does not replace an explicit controller reference. Laravel's routing examples import controller classes. Check the Laravel versions your package supports before relying on a particular controller-action syntax.

Expose route options through package configuration

If users should control the prefix or middleware, put those defaults in a package configuration file and merge them from the provider’s register() method. Laravel’s package documentation covers merging and publishing configuration.

 'tools',
    'route_middleware' => ['web'],
    'route_name_prefix' => 'acme-tools.',
];

The provider can use those values when it registers the routes:

mergeConfigFrom(
            __DIR__.'/../config/acme-tools.php',
            'acme-tools',
        );
    }

    public function boot(): void
    {
        $this->publishes([
            __DIR__.'/../config/acme-tools.php' => config_path('acme-tools.php'),
        ], 'acme-tools-config');

        Route::middleware(config('acme-tools.route_middleware', ['web']))
            ->prefix(config('acme-tools.route_prefix', 'tools'))
            ->name(config('acme-tools.route_name_prefix', 'acme-tools.'))
            ->group(function (): void {
                $this->loadRoutesFrom(__DIR__.'/../routes/web.php');
            });
    }
}

Choose these defaults based on what the package's routes need. Choose web according to route behavior, including whether routes need browser session support; a web.php filename alone does not determine that choice. An empty prefix removes the added URL segment. To let users disable the package routes, add and document a configuration option.

Laravel's mergeConfigFrom() merges only an array's top-level values. When users override a value inside a nested array, Laravel does not merge the missing values in that array. Keep route settings flat, or merge nested defaults yourself.

Document and verify route behavior

Tell package users whether routes load automatically, what URL prefix and middleware apply by default, and how to change those values. Also explain the route-name prefix, how to publish the configuration file, and whether users can disable route registration. Include an example of a named route so users can see the final name they should call.

Verify registration in a Laravel application that installs the package. Run php artisan route:list and check the package route’s URI, middleware, controller, and name. Then run php artisan route:cache and confirm the route remains available. loadRoutesFrom() skips the route file when Laravel has cached routes. After changing route definitions, clear and rebuild the route cache before treating a missing route as a package-registration bug. Laravel describes route caching and route inspection in its routing documentation.

Check these behaviors against every Laravel version your package supports. The examples here follow Laravel 13.x conventions; the Laravel 10.x package documentation provides a cross-version reference, but it does not establish compatibility with every release.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *