> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Package middleware registration and scope

> Examine the Laravel 13 Router implementation to learn how packages register middleware aliases, apply middleware explicitly, avoid overwriting groups, and verify behavior with route caching.

When you add HTTP features to a package, keep making middleware available separate from applying it to the consuming application's requests. If installing the package alone does not change the behavior of every route, it is easier to manage the impact of adoption and future compatibility.

This page assumes you are familiar with [package development basics](/en/advanced/package-development) and refers to the official Laravel `13.x` documentation and the Framework `v13.36.0` implementation. For how to write regular middleware, see [Middleware](/en/middleware).

## Separate registration, application, and execution

`Router::aliasMiddleware()` registers an entry in the Router's array, with the alias as the key and the class name as the value. It does not instantiate the middleware or apply it to any route.

```mermaid theme={null}
flowchart TD
    A["Provider boot"] --> B["Register name and class<br>with aliasMiddleware"]
    C["Route definition"] --> D["Specify the name to apply<br>with middleware"]
    B --> E["The request's route is determined"]
    D --> E
    E --> F["Expand aliases and groups<br>apply exclusions and priority"]
    F --> G["Pipeline executes the middleware"]
```

| Operation | Role | What it does not do on its own |
| - | - | - |
| `aliasMiddleware()` | Registers a mapping from a name to a class | Apply the middleware to requests |
| The route's `middleware()` | Assigns middleware to the target route | Provide the middleware class's own implementation |
| `middlewareGroup()` | Sets the contents of a named group | Add to the global middleware |
| Adding to the HTTP Kernel's global stack | Targets every request | Support per-route exclusion |

Alias names are part of your public API. Avoid built-in names such as `auth` and `throttle`, as well as generic names likely to collide with other packages, and add a package-specific prefix. If you register the same key again, `aliasMiddleware()` overwrites the previous mapping.

## Expose the alias from the provider

The following example creates middleware that adds a fixed identification header to the response. It is not an example of authentication, authorization, or access control. It assumes that Composer's PSR-4 maps `Acme\Courier\` to `src/` and that the provider is registered through [auto-discovery](/en/advanced/package-discovery) or manually.

```php src/Http/Middleware/AddCourierHeader.php theme={null}
<?php

namespace Acme\Courier\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AddCourierHeader
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        $response->headers->set('X-Acme-Courier', 'enabled');

        return $response;
    }
}
```

Use the Router in `boot()`. Because `boot()` arguments are injected from the service container, you do not need to automatically edit the consumer's `bootstrap/app.php` to register middleware.

```php src/CourierServiceProvider.php theme={null}
<?php

namespace Acme\Courier;

use Acme\Courier\Http\Middleware\AddCourierHeader;
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(Router $router): void
    {
        $router->aliasMiddleware('acme-courier.header', AddCourierHeader::class);
    }
}
```

Boot this provider as a regular provider. If you move alias registration into a deferred provider that runs only when another service is resolved, there is no guarantee that the alias will be registered by the time a route needs it.

### Consumers apply it per route

In the consuming application's `routes/web.php`, assign it only to the routes that need it.

```php routes/web.php theme={null}
<?php

use Illuminate\Support\Facades\Route;

Route::get('/courier-status', function () {
    return response()->json(['available' => true]);
})->middleware('acme-courier.header');
```

You can also skip providing an alias and specify the class name directly, as in `->middleware(AddCourierHeader::class)`. Choose based on whether you need to offer consumers a short name.

When the package itself provides routes, also declare the required middleware explicitly in the route file. `loadRoutesFrom()` does not automatically add `web` or `api`. For registration methods and how route caching is handled, see [Package route registration and caching](/en/advanced/package-routes).

## Let consumers choose application-wide application

If consumers want to apply the middleware to every `web` route in their application, they add the following configuration to their existing `withMiddleware()` callback. This example does not replace the existing configuration.

```php theme={null}
use Acme\Courier\Http\Middleware\AddCourierHeader;
use Illuminate\Foundation\Configuration\Middleware;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->web(append: [
        AddCourierHeader::class,
    ]);
})
```

Because this configuration uses the class name directly, it does not depend on the order in which aliases are registered. The scope is the `web` group, not the global stack. It is not automatically applied to `api` routes or to routes that have neither group.

<Warning>
  A design that applies middleware to all of `web` at package installation time is not compatible with a design where consumers apply it explicitly. Do not extend processing that affects authentication, sessions, response headers, external communication, and the like to every route through an automatic update.
</Warning>

## Router group operations behave differently

If your package provides its own group, use a unique name. The following example goes inside the provider's `boot(Router $router)`.

```php theme={null}
$router->middlewareGroup('acme-courier', [
    AddCourierHeader::class,
]);
```

Consumers can apply it with `->middleware('acme-courier')`. However, this group contains only the classes you specify; it does not inherit the session or CSRF protection from `web`.

There are also APIs for adding to existing groups, but the `v13.36.0` Router implementation has the following differences.

| Router method | When the group exists | When the group does not exist |
| - | - | - |
| `middlewareGroup($name, $items)` | Replaces the entire array | Creates it with the given array |
| `pushMiddlewareToGroup($name, $item)` | Appends to the end if the item is not already present | Creates an empty array and then appends |
| `prependMiddlewareToGroup($name, $item)` | Prepends to the start if the item is not already present | Does nothing |

If you set only your package's class with `middlewareGroup('web', [...])`, you replace the existing contents of `web`. Do not confuse it with the methods for adding. Also, calling `pushMiddlewareToGroup()` on a nonexistent `web` group does not restore the standard `web` group.

The duplicate check in the adding methods compares the registered values. An alias and a class name that point to the same class are different strings, so they are separate items at the registration stage. Use consistent notation, and do not assume that the same class written in different forms will be deduplicated at registration time.

### Registration order alone does not guarantee execution order

The Router expands the aliases and groups assigned to a route, processes exclusions, and then sorts by priority. Prepending or appending alone does not guarantee a strict ordering relative to authentication or route model binding.

In addition, the HTTP Kernel's `syncMiddlewareToRouter()` synchronizes the Kernel's groups to the Router using `middlewareGroup()`. If the Kernel's configuration is resynchronized later, the contents of groups you added to the Router directly may be replaced. Rather than competing to modify existing groups based on the boot order of packages, the basic approach is to consolidate configuration in the consuming application's `withMiddleware()`.

For features that require a particular order, such as after the session starts or after authentication, document that requirement in the installation instructions and verify it together with the consuming application's priority settings. Avoid having a package replace the application's entire priority list.

## The boundary between caching and verification

Do not place alias registration inside a `routesAreCached()` condition or in a route file. `loadRoutesFrom()` does not load the route file when a cache exists, but registration is still needed to resolve aliases that remain in cached routes at runtime. Register them every time in the provider's `boot()`.

If you change route assignments, rebuild the route cache in the consuming application.

```bash theme={null}
php artisan route:cache
php artisan route:list --path=courier-status -vv
```

Use `-vv` to expand and check group contents. However, a successful listing does not guarantee the processing inside the middleware or the use of sessions. You also need HTTP request tests.

The following method is added to a Feature test in a Laravel application that defines the `/courier-status` route above.

```php theme={null}
public function test_courier_header_is_applied(): void
{
    $this->get('/courier-status')
        ->assertOk()
        ->assertHeader('X-Acme-Courier', 'enabled');
}
```

| Case to check | Expected result |
| - | - |
| A route where the alias is only registered | The header is not added |
| A route assigned the alias | The header is added |
| A route assigned the class name directly | Behaves the same way |
| Booting a fresh application after creating the cache | The same route behaves the same way |
| Choosing to apply to all of `web` | Applied to the target `web` routes and does not spread beyond them |
| Configuring the consuming application's own groups and priority | Ordering relative to sessions, authentication, and binding meets the requirements |

Unit tests that check whether a group exists or inspect the alias array are a separate kind of verification from actual HTTP execution. In particular, verify caching not just by inspecting the Router in the same process, but with a fresh boot after the cache is created. If you use long-running workers, reload them according to your normal deployment procedure.

## Related pages

<Columns cols={2}>
  <Card title="Middleware" icon="layer-group" href="/en/middleware">
    Review the basics of creating middleware, applying it to routes, parameters, and priority.
  </Card>

  <Card title="Package route registration and caching" icon="route" href="/en/advanced/package-routes">
    Review how route loading relates to configuration when the cache is created.
  </Card>
</Columns>

## Primary sources consulted

* [Laravel documentation: Middleware](https://github.com/laravel/docs/blob/6bb0a3be3c623f7964c8277625a07b6df7f1de2e/middleware.md)
* [Laravel documentation: Service provider boot and dependency injection](https://github.com/laravel/docs/blob/6bb0a3be3c623f7964c8277625a07b6df7f1de2e/providers.md#the-boot-method)
* [Router: alias registration, group operations, and middleware expansion and sorting](https://github.com/laravel/framework/blob/v13.36.0/src/Illuminate/Routing/Router.php)
* [HTTP Kernel: syncMiddlewareToRouter](https://github.com/laravel/framework/blob/v13.36.0/src/Illuminate/Foundation/Http/Kernel.php)


## Related topics

- [Package route registration and caching](/en/advanced/package-routes.md)
- [Package service lifetime design](/en/advanced/package-service-lifetimes.md)
- [Deferred Service Providers](/en/advanced/deferred-provider.md)
- [Laravel Package Development](/en/advanced/package-development.md)
- [Adding package diagnostics to about](/en/advanced/package-about.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.