Laravel Routes are matched in the order they are declared


Example

This is a common gotcha with Laravel routes. Routes are matched in the order that they are declared. The first matching route is the one that is used.

This example will work as expected:

Route::get('/posts/{postId}/comments/{commentId}', 'CommentController@show');
Route::get('/posts/{postId}', 'PostController@show');

A get request to /posts/1/comments/1 will invoke CommentController@show. A get request to /posts/1 will invoke PostController@show.

However, this example will not work in the same manner:

Route::get('/posts/{postId}', 'PostController@show');
Route::get('/posts/{postId}/comments/{commentId}', 'CommentController@show');

A get request to /posts/1/comments/1 will invoke PostController@show. A get request to /posts/1 will invoke PostController@show.

Because Laravel uses the first matched route, the request to /posts/1/comments/1 matches Route::get('/posts/{postId}', 'PostController@show'); and assigns the variable $postId to the value 1/comments/1. This means that CommentController@show will never be invoked.