AutoRoute is a declarative routing library for Flutter that provides type-safe navigation through code generation. Instead of navigating with string-based route names, you define routes once and let AutoRoute generate strongly typed APIs.
This approach significantly reduces runtime navigation errors and improves refactoring safety.
Navigation complexity grows quickly in real apps. AutoRoute helps by:
It is especially useful when building apps with many screens or URL-based navigation.
AutoRoute uses annotations and build_runner to generate routing code. You define your routes in a router configuration file, then run the generator.
A minimal setup looks like this:
import 'package:auto_route/auto_route.dart';
part 'app_router.gr.dart';
@AutoRouterConfig()
class AppRouter extends $AppRouter {
@override
List<AutoRoute> get routes => [
AutoRoute(page: HomeRoute.page, initial: true),
AutoRoute(page: DetailsRoute.page),
];
}The part 'app_router.gr.dart'; line is required. Without it, the generated $AppRouter class will not be found and the code will not compile.
After defining routes, generate code with:
dart run build_runner build(or watch during development).
You can then navigate like this:
context.router.push(DetailsRoute(id: 42));Route arguments are checked at compile time.
AutoRoute is based on:
build_runner)It avoids common issues found in Navigator.pushNamed.
Use AutoRoute when:
AutoRoute also provides AutoTabsScaffold, a powerful widget for bottom navigation that preserves tab state automatically.
Avoid AutoRoute if:
In such cases, basic Navigator APIs may be sufficient.
A frequent error is forgetting to run build_runner after adding or changing routes. Hot Reload does not regenerate routing code.
Another mistake is mixing AutoRoute navigation with manual Navigator.push calls, which can lead to inconsistent behavior.
GoRouter is the most popular alternative. It offers declarative routing without code generation, but with less compile-time safety.
AutoRoute is a strong choice when correctness, structure, and scalability are priorities.
12 min • Jul 27, 2023
Read about the LeanCode approach to Flutter architecture. We highlight some of the design decisions that should be made when developing a feature in mobile apps. This includes our approach to dependency injection, state management, widget lifecycle, and data fetching.
5 min • Jan 29, 2025
Unfortunately, the Dart team has taken up the difficult decision of abandoning their work on the macros language feature. Although freezed is a powerful package, it comes with some costs. At some point, we decided to move forward and use alternative solutions for new code and projects. See our approach.
12 min • May 16, 2024
When a project grows, sooner or later, a need for sharing logic across multiple clients and a server arises. At LeanCode, we completed a project that extensively employed logic sharing successfully. In this article, we highlight the steps and architecture decisions of the picked solution.