FlutterInit doesn’t maintain two unrelated router codebases. One template — lib/src/routing/app_router.dart — branches on your navigation choice. In a Clean Architecture project, screens still live under lib/src/features/.../presentation/screens. Only the router API changes.
What you get with go_router
When navigation is go_router, the generator emits a GoRouter with path builders for onboarding, login, signup, forgot password, and home. Navigation looks like context.go / context.push. Deep links are URL-shaped. No build_runner step for routes.
DART
final GoRouter appRouter = GoRouter( // routes for onboarding, auth, home…);
What you get with AutoRoute
When navigation is auto_route, you get @AutoRouterConfig on a RootStackRouter, plus auto_route / auto_route_generator in pubspec.yaml. Screens are annotated @RoutePage(). You run build_runner to produce app_router.gr.dart. Navigation uses context.router.push / replace / pop.
Typed routes catch typos at compile time. The cost is codegen and a slightly heavier setup.
Clean Architecture stays the same
Either router:
Imports feature screens from the Clean/Feature-First tree (or MVVM ui/ paths when that’s your architecture)
Shares app_routes.dart and global_navigator.dart helpers
Must stay in the “modify with caution” zone in AGENTS.md — bad redirects break auth flows
Don’t put routing logic in widgets deep in the tree. Push through the central router.
When to choose which
Need
Prefer
Fast iteration, web-friendly paths, less tooling
go_router
Compile-time route args, large app with many screens
AutoRoute
GetX for state
GetX navigation is forced — not this pair
GetX state management forces the GetX router in FlutterInit. Otherwise you choose go_router or AutoRoute (or imperative Navigator).