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.

Was this helpful?