# Routing - [Introduction](#introduction) - [Basic Routing](#basic-routing) - [Route Parameters](#route-parameters) - [Named Routes](#named-routes) - [Route Groups](#route-groups) - [Middleware](#middleware) - [Prefixes](#prefixes) - [Layouts (Shell Routes)](#layouts-shell-routes) - [Context-Free Navigation](#context-free-navigation) - [Route Middleware](#route-middleware) - [Inspecting Routes](#inspecting-routes) ## Introduction The most basic Magic routes accept a URI and a closure, providing a very simple and expressive method of defining routes and behavior without complicated routing configuration files. All routes for your application are defined in the `lib/routes` directory. These files are loaded by the `RouteServiceProvider`, which is included in your `config/app.dart` by default. ## Basic Routing The most basic route definitions involve calling a method on the `MagicRoute` facade: ```dart MagicRoute.page('/', () => HomePage()); ``` ### Route Methods Use the `page` method to define full-screen page routes: ```dart // Simple page MagicRoute.page('/greeting', () => Text('Hello World')); // Controller action MagicRoute.page('/dashboard', () => DashboardController.instance.index()); // Inline widget MagicRoute.page('/about', () => AboutPage()); ``` ### The Initial Route Configure your application's initial route via `MagicApplication`: ```dart runApp( MagicApplication( initialRoute: '/dashboard', // ... ), ); ``` ## Route Parameters ### Required Parameters Sometimes you need to capture segments of the URI. For example, to capture a user's ID: ```dart MagicRoute.page('/user/:id', (id) { return UserProfileView(userId: id); }); ``` You may define as many route parameters as required: ```dart MagicRoute.page('/posts/:postId/comments/:commentId', (postId, commentId) { return CommentView(postId: postId, commentId: commentId); }); ``` > [!NOTE] > Magic uses `:param` syntax (like Express.js) instead of Laravel's `{param}` syntax. ## Named Routes Named routes allow convenient generation of URLs or redirects for specific routes. Specify a name by chaining the `name` method: ```dart MagicRoute.page('/user/profile', () => ProfileView()) .name('profile'); MagicRoute.page('/user/:id', (id) => UserView(id: id)) .name('user.show'); ``` ### Navigating To Named Routes Once you have assigned a name to a route, you may use it when navigating: ```dart // Navigate to named route MagicRoute.toNamed('profile'); // With path parameters MagicRoute.toNamed('user.show', params: {'id': '42'}); // With query parameters MagicRoute.toNamed('search', query: {'q': 'flutter'}); ``` ## Route Groups Route groups allow you to share route attributes, such as middleware or prefixes, across multiple routes. ### Middleware Assign middleware to all routes within a group: ```dart MagicRoute.group( middleware: ['auth'], routes: () { MagicRoute.page('/dashboard', () => DashboardView()); MagicRoute.page('/profile', () => ProfileView()); }, ); ``` ### Prefixes Add a path prefix to all routes in a group: ```dart MagicRoute.group( prefix: '/admin', middleware: ['auth', 'admin'], routes: () { MagicRoute.page('/', () => AdminDashboard()); // /admin MagicRoute.page('/users', () => AdminUsers()); // /admin/users MagicRoute.page('/settings', () => AdminSettings()); // /admin/settings }, ); ``` ### Nested Groups Groups can be nested. Child groups inherit parent attributes: ```dart MagicRoute.group( prefix: '/admin', middleware: ['auth'], routes: () { MagicRoute.group( prefix: '/users', routes: () { MagicRoute.page('/', () => UserList()); // /admin/users MagicRoute.page('/:id', (id) => UserShow(id: id)); // /admin/users/:id }, ); }, ); ``` ### Layouts (Shell Routes) Assign a persistent layout to all routes within a group. The layout persists while child pages change—perfect for tab bars, navigation rails, and sidebars: ```dart MagicRoute.group( layout: (child) => AppLayout(child: child), middleware: ['auth'], routes: () { MagicRoute.page('/', () => DashboardView()); MagicRoute.page('/monitors', () => MonitorsView()); MagicRoute.page('/settings', () => SettingsView()); }, ); ``` Your layout widget should accept and render the `child` parameter: ```dart class AppLayout extends StatelessWidget { final Widget child; const AppLayout({required this.child, super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Row( children: [ AppSidebar(), Expanded(child: child), // Child pages render here ], ), ); } } ``` > [!TIP] > Use layouts for any UI that should persist across page navigation, such as sidebars, bottom navigation bars, or headers. ## Context-Free Navigation You may navigate from anywhere in your application—controllers, services, or pure Dart classes—without needing `BuildContext`: ```dart // Replace current route MagicRoute.to('/dashboard'); // Push onto navigation stack (back button works) MagicRoute.push('/details'); // Go back MagicRoute.back(); // Replace current route (no back) MagicRoute.replace('/home'); // With query parameters MagicRoute.to('/search', query: {'q': 'flutter'}); ``` ### From Controllers ```dart class AuthController extends MagicController { Future logout() async { await Auth.logout(); MagicRoute.to('/login'); // No context needed! } } ``` ## Route Middleware Assign middleware to individual routes using the `middleware` method: ```dart MagicRoute.page('/profile', () => ProfileView()) .middleware(['auth']); MagicRoute.page('/admin', () => AdminPanel()) .middleware(['auth', 'admin']); ``` See the [Middleware documentation](/basics/middleware) for details on creating custom middleware. ## Inspecting Routes Magic CLI provides a command to list all registered routes: ```bash magic route:list ``` Output: ``` +---------------------+------------+----------+ | URI | Middleware | File | +---------------------+------------+----------+ | / | auth | app.dart | | /monitors | auth | app.dart | | /auth/login | - | auth.dart| | /settings/team | auth | app.dart | +---------------------+------------+----------+ ``` > [!TIP] > Run `magic route:list` after making routing changes to verify your routes are registered correctly.