Named Routes vs go_router Flutter: Key Differences and Usage
named routes provide a simple, built-in way to navigate using string route names, suitable for small apps. The go_router package offers a more powerful, declarative, and flexible routing system with deep linking and nested routes, ideal for larger or complex apps.Quick Comparison
This table summarizes key factors comparing Flutter's built-in named routes and the go_router package.
| Factor | Named Routes | go_router |
|---|---|---|
| Setup Complexity | Simple to set up with MaterialApp | Requires adding go_router package and setup |
| Routing Style | Imperative with string route names | Declarative with typed routes and URL patterns |
| Deep Linking | Limited support, manual handling | Built-in deep linking support |
| Nested Routes | No native support, manual workarounds | Native nested routing support |
| Route Parameters | Passed via arguments, less type-safe | Typed parameters in route paths |
| Navigation Guards | No built-in guards | Supports redirect and guard logic |
| Scalability | Best for small/simple apps | Designed for medium to large apps |
Key Differences
Named routes in Flutter use a simple map of string route names to widget builders inside MaterialApp. Navigation happens by calling Navigator.pushNamed with a route name. This approach is straightforward but can become hard to manage as the app grows, especially with complex navigation flows or deep linking.
On the other hand, go_router is a third-party package that provides a declarative routing API. It uses URL-like route patterns, supports nested routes, and allows passing typed parameters directly in the route path. It also has built-in support for deep linking and navigation guards, making it easier to handle authentication flows or conditional redirects.
While named routes are part of Flutter's core and require no extra dependencies, go_router requires adding a package but offers more features and better scalability for complex apps.
Named Routes Code Comparison
This example shows how to define and navigate using Flutter's built-in named routes.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: '/', routes: { '/': (context) => HomeScreen(), '/details': (context) => DetailsScreen(), }, ); } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Home')), body: Center( child: ElevatedButton( onPressed: () => Navigator.pushNamed(context, '/details'), child: Text('Go to Details'), ), ), ); } } class DetailsScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Details')), body: Center(child: Text('Details Screen')), ); } }
go_router Equivalent
This example shows the same navigation using the go_router package with declarative routes.
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; void main() { final GoRouter router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => HomeScreen(), ), GoRoute( path: '/details', builder: (context, state) => DetailsScreen(), ), ], ); runApp(MyApp(router: router)); } class MyApp extends StatelessWidget { final GoRouter router; MyApp({required this.router}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: router, ); } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Home')), body: Center( child: ElevatedButton( onPressed: () => context.go('/details'), child: Text('Go to Details'), ), ), ); } } class DetailsScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Details')), body: Center(child: Text('Details Screen')), ); } }
When to Use Which
Choose named routes when building small or simple Flutter apps that need quick and easy navigation without extra dependencies. They are straightforward and good for apps with limited screens and simple flows.
Choose go_router when your app requires complex navigation, such as nested routes, deep linking, route parameters, or navigation guards. It is better suited for medium to large apps where maintainability and scalability are important.