Answer
Overview
AutoRoute is a code-generation package for Flutter navigation with type-safe routes, nested routing, deep linking, and guards. It's an alternative to Navigator 2.0 with less boilerplate.
Installation
Add to
text
pubspec.yamlyamldependencies: auto_route: ^7.8.0 dev_dependencies: auto_route_generator: ^7.3.0 build_runner: ^2.4.0
Setup
1. Define Routes
lib/app_router.dart:
dartimport 'package:auto_route/auto_route.dart'; () class AppRouter extends $AppRouter { List<AutoRoute> get routes => [ AutoRoute(page: HomeRoute.page, initial: true), AutoRoute(page: ProfileRoute.page), AutoRoute(page: SettingsRoute.page), ]; }
2. Annotate Pages
dartimport 'package:auto_route/auto_route.dart'; () class HomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Home')), body: Center( child: ElevatedButton( onPressed: () { context.router.push(ProfileRoute(userId: '123')); }, child: Text('Go to Profile'), ), ), ); } }
3. Generate Code
bashflutter pub run build_runner build --delete-conflicting-outputs
Generates
text
app_router.gr.dart4. Initialize Router in main.dart
dartvoid main() { runApp(MyApp()); } class MyApp extends StatelessWidget { final _appRouter = AppRouter(); Widget build(BuildContext context) { return MaterialApp.router( routerConfig: _appRouter.config(), ); } }
Navigation
Push Route
dart// Programmatic navigation context.router.push(ProfileRoute(userId: '123')); // Named route context.router.pushNamed('/profile/123');
Replace Route
dart// Replace current route context.router.replace(LoginRoute());
Pop Route
dart// Go back context.router.pop(); // Pop with result context.router.pop('success');
Pop Until
dart// Pop until condition met context.router.popUntil((route) => route.settings.name == 'HomeRoute'); // Pop to root context.router.popUntilRoot();
Route Parameters
Path Parameters
dart() class AppRouter extends $AppRouter { List<AutoRoute> get routes => [ AutoRoute(page: ProfileRoute.page, path: '/profile/:userId'), ]; } () class ProfilePage extends StatelessWidget { final String userId; // Auto-injected from path const ProfilePage({required this.userId}); Widget build(BuildContext context) { return Text('User ID: $userId'); } } // Navigate context.router.push(ProfileRoute(userId: '123')); // /profile/123
Query Parameters
dart() class SearchPage extends StatelessWidget { final String? query; final int? page; const SearchPage({this.query, this.page}); Widget build(BuildContext context) { return Text('Query: $query, Page: $page'); } } // Navigate with query params context.router.pushNamed('/search?query=flutter&page=2');
Nested Navigation (Tabs)
dart() class DashboardPage extends StatelessWidget { Widget build(BuildContext context) { return AutoTabsRouter( routes: [ HomeRoute(), ProfileRoute(), SettingsRoute(), ], builder: (context, child) { final tabsRouter = AutoTabsRouter.of(context); return Scaffold( body: child, bottomNavigationBar: BottomNavigationBar( currentIndex: tabsRouter.activeIndex, onTap: tabsRouter.setActiveIndex, items: [ BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'), BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'), BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'), ], ), ); }, ); } }
Guards (Route Protection)
Protect routes with authentication guards.
dartclass AuthGuard extends AutoRouteGuard { final AuthService authService; AuthGuard(this.authService); void onNavigation(NavigationResolver resolver, StackRouter router) { if (authService.isAuthenticated) { resolver.next(true); // Allow navigation } else { resolver.redirect(LoginRoute()); // Redirect to login } } } // Register guard () class AppRouter extends $AppRouter { final AuthService authService; AppRouter(this.authService); List<AutoRoute> get routes => [ AutoRoute(page: LoginRoute.page), AutoRoute( page: ProfileRoute.page, guards: [AuthGuard(authService)], // Protected ), ]; }
Deep Linking
dart() class AppRouter extends $AppRouter { List<AutoRoute> get routes => [ AutoRoute(page: HomeRoute.page, path: '/'), AutoRoute(page: ProductRoute.page, path: '/product/:id'), ]; } // Deep link: myapp://product/123 // Navigates to ProductPage with id='123'
Route Observers
Track navigation events (analytics, logging).
dartclass MyObserver extends AutoRouterObserver { void didPush(Route route, Route? previousRoute) { print('Pushed: ${route.settings.name}'); } void didPop(Route route, Route? previousRoute) { print('Popped: ${route.settings.name}'); } } // Register observer MaterialApp.router( routerConfig: _appRouter.config( navigatorObservers: () => [MyObserver()], ), );
Redirects
dart() class AppRouter extends $AppRouter { List<AutoRoute> get routes => [ AutoRoute(page: HomeRoute.page), RedirectRoute(path: '/old-path', redirectTo: '/new-path'), ]; }
Route Transitions
Custom page transitions.
dartAutoRoute( page: ProfileRoute.page, transitionsBuilder: TransitionsBuilders.slideLeft, durationInMilliseconds: 300, ) // Available transitions: // - slideLeft, slideRight, slideTop, slideBottom // - fadeIn // - zoomIn // - noTransition
Comparison: Navigator 2.0 vs AutoRoute
| Feature | Navigator 2.0 | AutoRoute |
|---|---|---|
| Boilerplate | High | Low ✅ |
| Type safety | Manual | Auto-generated ✅ |
| Deep linking | Complex setup | Built-in ✅ |
| Nested routing | Manual | Simple ✅ |
| Guards | Manual | Built-in ✅ |
| Code generation | No | Yes |
Full Example
lib/pages/home_page.dart:
dart() class HomePage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Home')), body: Center( child: ElevatedButton( onPressed: () => context.router.push(ProfileRoute(userId: '123')), child: Text('Go to Profile'), ), ), ); } }
lib/pages/profile_page.dart:
dart() class ProfilePage extends StatelessWidget { final String userId; const ProfilePage({('userId') required this.userId}); Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Profile')), body: Center(child: Text('User: $userId')), ); } }
lib/app_router.dart:
dart() class AppRouter extends $AppRouter { List<AutoRoute> get routes => [ AutoRoute(page: HomeRoute.page, initial: true), AutoRoute(page: ProfileRoute.page, path: '/profile/:userId'), ]; }
Build Commands
bash# Generate routes flutter pub run build_runner build --delete-conflicting-outputs # Watch mode flutter pub run build_runner watch
Best Practices
dart// ✅ Use path parameters for required data AutoRoute(page: ProfileRoute.page, path: '/profile/:userId') // ✅ Use guards for protected routes AutoRoute(page: DashboardRoute.page, guards: [AuthGuard()]) // ✅ Use nested routing for tabs AutoTabsRouter(routes: [...]) // ❌ Don't mix AutoRoute with Navigator.push (use one system)
Learn more: AutoRoute Documentation