Routing
Last updated: 04/17/2026 · Written by Agent0
Routing
All routes are defined in routes/web.php. The router matches incoming requests to a controller method, runs any middleware, and dispatches the action. StackCTL supports GET, POST, PUT, and DELETE methods.
Basic Routes
A route maps a URI and HTTP method to a Controller@method string.
$router->get('/articles', 'ArticlesController@index');
$router->post('/articles/save', 'ArticlesController@save');
The format is always 'ControllerName@methodName'. StackCTL will instantiate the controller and call the method automatically.
All supported methods
$router->get('/path', 'Controller@method');
$router->post('/path', 'Controller@method');
$router->put('/path', 'Controller@method');
$router->delete('/path', 'Controller@method');
Note: HTML forms only support GET and POST. To use PUT or DELETE from a form, include a hidden _method field and StackCTL will handle the override automatically:
<form method="POST" action="/articles/5">
<input type="hidden" name="_method" value="PUT">
...
</form>
Route Parameters
Dynamic segments in a URI are defined using curly braces. They are passed as arguments to the controller method in the order they appear.
// Route definition
$router->get('/articles/{id}', 'ArticlesController@show');
// Controller method
public function show($id)
{
$article = Query::table('articles')->find((int)$id);
...
}
Multiple parameters work the same way:
$router->get('/categories/{category}/articles/{id}', 'ArticlesController@show');
public function show($category, $id) { ... }
Tip: Static routes always match before dynamic ones. So /articles/form will never be caught by /articles/{id} — even if both are registered.
Middleware on Routes
Chain ->middleware() onto any route to protect it. See the Auth & Middleware doc for the full list of built-in middleware options.
$router->get('/dashboard', 'DashboardController@index')
->middleware('auth');
// Multiple middleware — applied in order
$router->get('/admin', 'AdminController@index')
->middleware(['auth', 'role:admin']);
Route Groups
Groups apply shared middleware and/or a URI prefix to a set of routes at once. This keeps web.php clean and avoids repeating ->middleware() on every route.
Middleware group
$router->group(['middleware' => 'auth'], function ($router) {
$router->get('/dashboard', 'DashboardController@index');
$router->get('/profile', 'ProfileController@index');
$router->post('/profile', 'ProfileController@update');
});
Prefix + middleware group
$router->group(['prefix' => '/admin', 'middleware' => 'role:admin'], function ($router) {
$router->get('/users', 'AdminController@users'); // → /admin/users
$router->get('/settings', 'AdminController@settings'); // → /admin/settings
});
Nested groups
Groups can be nested — middleware stacks from the outside in, so both layers apply to the innermost routes.
$router->group(['middleware' => 'auth'], function ($router) {
$router->group(['middleware' => 'role:admin'], function ($router) {
$router->get('/admin', 'AdminController@index');
// Requires: logged in AND role is admin
});
});
Named Routes
Assign a name to a route with ->name() and use the route() helper anywhere in your app instead of hardcoding URLs. If the URI ever changes, you only update it in one place.
// In web.php
$router->get('/dashboard', 'DashboardController@index')->name('dashboard');
$router->get('/articles/{id}', 'ArticlesController@show')->name('articles.show');
// In a view or controller
<a href="<?= route('dashboard') ?>">Dashboard</a>
// With a parameter
<a href="<?= route('articles.show', [$article->id]) ?>">Read More</a>
Redirect Routes
Register a simple redirect without creating a controller method.
$router->redirect('/doc', '/docs'); // 302 by default
$router->redirect('/old-page', '/new-page', 301); // permanent redirect
How web.php is Organized
The default routes/web.php is structured into three sections that cover most app patterns:
// 1. Public routes — no middleware, accessible to everyone
$router->get('/', 'HomeController@index');
// 2. Guest routes — only accessible when NOT logged in
$router->group(['middleware' => 'guest'], function ($router) {
$router->get('/login', 'AuthController@showLogin');
$router->post('/login', 'AuthController@login');
$router->get('/register', 'AuthController@showRegister');
$router->post('/register','AuthController@register');
});
// 3. Authenticated routes — require login
$router->group(['middleware' => 'auth'], function ($router) {
$router->get('/dashboard', 'DashboardController@index');
// Add your resource routes here
$router->get('/articles', 'ArticlesController@index');
$router->get('/articles/form', 'ArticlesController@form');
$router->get('/articles/form/{id}', 'ArticlesController@form');
$router->post('/articles/save', 'ArticlesController@save');
$router->post('/articles/delete/{id}', 'ArticlesController@delete');
});
The // [STACKCTL_ROUTES] comment inside the auth group is the insertion point used by php stack create:resource when suggesting new routes — keep it in place.