minaremonshaker's avatar

How does Laravel determine route specificity and matching priority?

I'm trying to get a solid grasp on how Laravel handles route specificity when multiple routes could potentially match a given URI. From what I've read, routes are matched based on the order they're defined, with more specific (static) routes taking precedence over parameterized ones. But I'd love some clarification and examples from experienced devs.

For instance:

  • If I have Route::get('/foo/bar', 'ControllerA') defined before Route::get('/foo/{slug}', 'ControllerB'), does / foo/bar always hit ControllerA first due to specificity?

  • What if both are parameterized, like /foo/{id} vs /foo/{slug}?

  • Any gotchas with route groups, middleware, or API routes?

Also, best practices for ordering routes in routes/web.php or routes/api.php to avoid surprises? php artisan route:list helps verify, but understanding the rules upfront would save headaches in larger apps.

0 likes
2 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

Great questions! In Laravel, route matching is order-based: Laravel checks routes from top to bottom in your routes file and matches the first one that fits. Static routes (/foo/bar) always take precedence over parameterized routes (/foo/{slug}) if they come first.

Examples:

Route::get('/foo/bar', 'ControllerA');
Route::get('/foo/{slug}', 'ControllerB');

A request to /foo/bar hits ControllerA. If you flip the order, /foo/bar would match the /{slug} route and hit ControllerB.

If you define two parameterized routes like /foo/{id} and /foo/{slug}, the first one wins for any matching URI segment.

Route groups and middleware don't change matching order, but they can affect which controllers and middleware get triggered. For best practices:

  • Put static routes before parameterized ones.
  • Order from most specific to most general.
  • Use php artisan route:list to double-check.

Gotchas? Watch for duplicate/conflicting parameterized routes—they can be a debugging headache!

martinbean's avatar

If I have Route::get('/foo/bar', 'ControllerA') defined before Route::get('/foo/{slug}', 'ControllerB'), does / foo/bar always hit ControllerA first due to specificity?

@minaremonshaker First one wins. This is why when you use resource routes, Laravel will register the create route (i.e. /articles/create) before the show route (/articles/{article}), otherwise the create portion in /articles/create would get interpreted as the {article} parameter, and try and find an article with that identifier.

What if both are parameterized, like /foo/{id} vs /foo/{slug}?

Then unless you have parameter constraints on the routes, only one will get matched. You can do something like this:

Route::get('foo/{id}', […])->whereNumber('id');

Route::get('foo/{slug}', […])->whereAlpha('slug');

But why? Why would you have two routes for the same URI like this? It’s also not going to work if a slug for a “foo” happens to just be numbers only, as it’ll then get matched by the foo/{id} route.

Please or to participate in this conversation.