Routing Guide
Air Framework leverages go_router for navigation but simplifies it by allowing each module to define its own routes.
Defining Routes
Section titled “Defining Routes”Each module contributes to the global routing table by returning a list of AirRoute objects.
class CatalogModule extends AppModule { @override List<AirRoute> get routes => [ AirRoute( path: '/catalog', builder: (context, state) => const CatalogView(), routes: [ AirRoute( path: ':id', builder: (context, state) => ProductDetailView(id: state.pathParameters['id']!), ), ], ), ];}Navigation
Section titled “Navigation”Since it’s built on go_router, you can use all standard navigation methods.
context.go('/catalog');context.push('/catalog/123');Shell Routes (Persistent Layouts)
Section titled “Shell Routes (Persistent Layouts)”You can define shell routes for persistent UIs (like bottom navigation bars).
AirRoute( path: '/app', builder: (context, state) => MainScaffold(child: state.child), routes: [ AirRoute(path: 'home', builder: (_, __) => HomeView()), AirRoute(path: 'settings', builder: (_, __) => SettingsView()), ],)Route Aggregation
Section titled “Route Aggregation”The ModuleManager collects all routes from all registered modules and provides them to the AirRouter, which builds the final configuration for MaterialApp.router.
AirRouter Singleton
Section titled “AirRouter Singleton”AirRouter is a singleton — access the same instance anywhere in your app without passing it around.
// In main.dartrunApp(MaterialApp.router( routerConfig: AirRouter().router,));
// From anywhere else — same instanceAirRouter().router.go('/catalog');Navigation Guards
Section titled “Navigation Guards”Use go_router’s redirect parameter inside an AirRoute to protect routes based on authentication state or permissions.
class AuthModule extends AppModule { @override List<AirRoute> get routes => [ AirRoute( path: '/dashboard', builder: (context, state) => const DashboardView(), redirect: (context, state) { // Redirect to login if user is not authenticated final isLoggedIn = AuthFlows.isLoggedIn.value; if (!isLoggedIn) return '/login'; return null; // null = allow navigation }, ), AirRoute( path: '/login', builder: (context, state) => const LoginView(), ), ];}Guards compose naturally — every module can protect its own routes independently. There’s no need for a global router with a massive redirect function.