Conversation
|
Maybe I'm misunderstanding your use case, but IMO it is the responsibility of the package to adapt to your applications needs, not the other way around. If the package needs to know where your home route lives, they should make you explicitly tell them where it is with a config value, not hardcode a "saas.team-selector" route name into their code that you must adapt to. |
|
Fair point, the home page is a simple example — let me try to paint a clearer picture. Think of an application made of 10 packages, each adding its own routes. These packages need to reference each other's routes for navigation, redirects, and so on. Today, the only clean way to handle this is through shared config: every package exposes a config file, the consumer publishes it, wires up the route names, and every package reads from it at boot. It works — but it's a lot of moving parts just to say "this name points here". Aliases simplify exactly that. One line, no config files, no cross-package wiring. And since aliases are cached alongside the route collection, there's no extra cost at runtime either. The goal is just to make things simpler — not to replace existing patterns, just to remove unnecessary friction when the use case is straightforward. |
|
Are these 10 packages all 3rd party, or do you control all/some of them? If they're all 3rd party, it seems odd/uncommon for them to need to know about each other and the associated routes, as this would create a bit of a rat's nest of coupling. I also don't completely follow how this is cleaner/simpler than the config solution, but I'll also admit this is never a problem I've run into. |
|
To clarify: these aren't third-party packages — I own and maintain all of them,colleagues too. So the problem isn't compatibility, it's the configuration overhead that quietly accumulates as a project grows. The bigger the project, the easier it is to lose track of which config controls what, and with many packages it quickly turns into an endless web of settings spread across many different files. The way I think about aliases is as semantic connections — a way for a package to declare the purpose of a route rather than just its name. Take Filament as an example: if its packages could declare that a given page serves as, say, the "dashboard entry point", other packages could connect to that concept without needing to know the exact route name or wiring up config manually. A practical everyday example: Laravel itself expects a route named Route::alias('auth.login', ['login']);No extra config, no workarounds, no It's also worth pointing out that this change doesn't alter how Laravel works today in any way. It purely adds optional functionality — if you never call That said, I fully understand your point and I know this reflects my own vision of how things should work. If the feature itself feels too opinionated for the framework core, maybe a lighter alternative would be to make the |
|
I'm having a hard time understanding this and I've worked with modules etc.. So what is the problem exactly of just referencing the original route name in those said packages if it's all your controlled code? Why is the route not named "saas.team-selector" to begin with if it's used across multiple different packages? surely it has only one meaning what the page represents or does. If you're using those packages across multiple different projects then it definitely should be a configuration file, as finding all routes you need to alias is way harder than looking at a config file. |
|
Hi @donnysim, The key point is that these packages are not designed for a single application — they are reusable building blocks that can be composed together to build different applications. Each application may define its own route structure, its own naming conventions, and its own entry points. A package like This is exactly why a centralized // routes/aliases.php
Route::alias('auth.login', ['login']);
Route::alias('auth.logout', ['logout']);
Route::alias('auth.register', ['register']);
Route::alias('auth.password.request', ['password.request']);
// ...Everything in one place, easy to find, easy to understand. As for the packages that would benefit immediately from this today — without any custom setup — here is a concrete list:
All of these today require you to either match their expected route names exactly, or work around them. Aliases would let each package declare what it needs and let the application wire things up in one place, cleanly. |
|
Beyond the modular package scenario, there are several other situations where route name aliases would be immediately useful: 1. Renaming routes without breaking existing code // old name kept alive while you migrate references gradually
Route::alias('dashboard.index', ['home']);2. Localization / multi-tenant applications 3. API versioning bridges 4. Cleaner package interoperability 5. Backwards compatibility in open source packages I'm aware these are fairly specific scenarios and this may not be something everyone needs. But that's exactly the point — it's entirely optional. If you never call Beyond the practical side though, I think introducing a semantic layer to route naming could be genuinely valuable for the Laravel ecosystem as a whole. Being able to say "this route serves as the application entry point" or "this is where authentication happens" — independently of what it's actually called — makes code more expressive, packages more interoperable, and applications easier to reason about. That kind of shared vocabulary, even if optional, tends to have a positive ripple effect across the ecosystem over time. |
If you have a single name, it ain't that hard to change, whereas if you have multiple aliases it will become even harder.
Translating route names is the worst idea ever. You cache them once, you don't translate them every time nor reference random route string that come from who knows where.
Duplicating a route and pointing to the same controller ain't that hard and keeps all v2 routes in one place instead of scattered across multiple versions. Also, if you're providing the same v1 for v2 you're risking oof breaking the v2 or v1 by changing the same code.
If a package allows you to choose, that means it should also include a config option and if it has a config why bother with alias where configs usually contain way more than just routes which most of the time - you'll want them too.
Configs already solve this because it's not tied to authors route name but yours. Local code should never need aliases, it just creates a separation issue where a single route could be reference by different name and it's just harder to find. Packages should not enforce implicit logic, they should be explicit about their expectations and needs. What you're getting with these aliases is implicit logic for packages where you have no idea why they're there whereas a config file is explicit. All your named packages have one or another way to change the default expectations via configuration as for aliases feel like cutting corners to enforce package needs onto the app instead of inverse. |
|
These are all fair and well-reasoned points, and I appreciate the detailed feedback. You're right that configs are explicit, and explicitness is generally a virtue. I won't argue against that. But I'd push back slightly on the framing that aliases are implicit in a negative sense — a On the individual points:
The core of my argument isn't that aliases replace configs — and I want to be clear on this. Both approaches are perfectly valid and they don't get in each other's way at all. A project can use configs for complex package configuration and aliases for the specific, lightweight case of saying "this name means this route". One doesn't invalidate the other. What I find interesting about aliases, beyond the practical side, is the possibility of introducing a semantic layer to route naming. Being able to express that a route serves a purpose — independently of what it's actually called — could help create a kind of shared vocabulary across packages and applications. I think that kind of harmony, even if entirely optional, could be a quiet but positive contribution to the ecosystem over time. That said, I have the utmost respect for your perspective and for the care you're putting into this review. If the consensus is that configs are always the right tool here, I genuinely accept that. I just think this is a conversation worth having. |
|
Thanks for your pull request to Laravel! Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include. If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions! |
Summary
This PR introduces a first-class concept of route name aliases — the ability to assign one or more alternative names to an already-named route, without duplicating the route registration itself.
route('app')androute('saas.team-selector')will now resolve to the exact same URL asroute('home'), with no duplicate entries in the route collection.Motivation
The need for this feature emerges naturally in modular Laravel applications, where multiple independent packages contribute routes and expect to navigate between each other using well-known route names.
A concrete example: consider an application composed of two packages:
GET /with the namehome.saas.team-selector.app.All three names refer to the same route. Today, the only workarounds are:
route:listoutput.Approach
This implementation takes a deliberate design decision: aliases live on the name, not on the route.
Rather than creating new
Routeinstances, aliases are stored as a simple map ofalias → original namedirectly inside theRouter. TheUrlGeneratorresolves aliases transparently at call time, soroute('alias')behaves identically toroute('original').This keeps the route collection clean and avoids any runtime overhead from duplicate route matching.
Key design choices
Router::addAlias(string $aliasName, string $originalName)— stores the alias map inside the Router itself, so it is serialized as part ofbootstrap/cache/routes-v7.phpwith no additional cache file needed.UrlGenerator::route()— resolves aliases transparently before delegating to the original implementation.route:list --with-aliases(or-a) — a new flag has been added to theroute:listcommand. By default aliases are hidden to keep the output clean; passing-areveals them inline next to the original route name:Route::alias()— provides a clean, expressive API at the route definition level.UrlGenerator::route(). The resolution order is strict: real route names always take priority over aliases. If a route namedappexists in the route collection, it will be resolved directly and the alias map is never consulted. The alias lookup only kicks in when no real route matches the given name. This means a real route can never be silently shadowed by an alias, with no extra validation logic needed anywhere else.Open questions
route:list -ashow aliases as a separate column, or inline as in the current implementation?->alias('other-name')be supported as a chainable alternative toRoute::alias()?route:alias?