Flutter go_router Navigation
The built-in Navigator handles simple apps. Apps with web addresses, deep links, and login checks need more power. The go_router package, maintained by the Flutter team, adds URL-style paths, parameters, and automatic redirects with little code.
Why Use go_router
- Every screen has a URL-like path, which works on the web and in deep links.
- Path parameters carry values such as a product number.
- Redirect rules guard private screens.
- Nested routes build tabs and shells with persistent navigation bars.
Installing the Package
Run this command inside your project:
flutter pub add go_router
Flutter adds the latest compatible version to pubspec.yaml.
Setting Up the Router
Create a GoRouter object that lists every path. Use MaterialApp.router instead of the regular MaterialApp.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
final GoRouter router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/about',
builder: (context, state) => AboutScreen(),
),
],
);
void main() {
runApp(MaterialApp.router(routerConfig: router));
}
URL path Screen
───────── ───────────
/ HomeScreen
/about AboutScreen
/product/42 ProductScreen (id = 42)
Go and Push
The package offers two ways to move.
| Call | Behavior |
|---|---|
| context.go('/about') | Replaces the navigation stack with the new path |
| context.push('/about') | Adds a screen on top of the current one |
| context.pop() | Returns to the previous screen |
Use go for moves between main sections. Use push for temporary detail screens that need a back button.
Path Parameters
A colon marks a variable part of the path.
GoRoute(
path: '/product/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return ProductScreen(id: id);
},
),
// Opening it
context.go('/product/42');
The value 42 arrives as text. Convert it with int.parse(id) when the screen needs a number.
Query Parameters
Optional values travel after a question mark, such as /search?term=shoes.
GoRoute(
path: '/search',
builder: (context, state) {
final term = state.uri.queryParameters['term'] ?? '';
return SearchScreen(term: term);
},
),
Nested Routes
A child route lives inside a parent and builds its path from the parent path.
GoRoute(
path: '/settings',
builder: (context, state) => SettingsScreen(),
routes: [
GoRoute(
path: 'privacy',
builder: (context, state) => PrivacyScreen(),
),
],
),
The child opens at /settings/privacy. Notice the child path has no leading slash.
Redirects for Login Protection
A redirect function runs before every navigation. Return a new path to divert the user, or return null to allow the move.
bool isLoggedIn = false;
final GoRouter router = GoRouter(
redirect: (context, state) {
final goingToLogin = state.matchedLocation == '/login';
if (!isLoggedIn && !goingToLogin) {
return '/login';
}
return null;
},
routes: [ /* routes here */ ],
);
User opens /profile
│
▼
Logged in? ── yes ──→ show /profile
│ no
▼
redirect to /login
Error Page
Set errorBuilder to show a friendly page when someone enters an unknown path.
GoRouter(
errorBuilder: (context, state) => NotFoundScreen(),
routes: [ /* routes here */ ],
);
ShellRoute for Persistent Navigation
A ShellRoute wraps several routes in a shared layout, such as a scaffold with a bottom bar. The bar stays on screen while the inner page changes. Use StatefulShellRoute when each tab must remember its own scroll position and history.
Navigator or go_router
| Situation | Better Choice |
|---|---|
| Small app, few screens | Navigator with named routes |
| Web app with shareable links | go_router |
| Login guards and deep links | go_router |
Check the package page on pub.dev for the latest API details, because routing packages evolve between releases.
Web Behavior
On the web, go_router connects Flutter screens to the browser address bar. Users bookmark a page, refresh it, and share the link. The browser back and forward buttons walk through the navigation history. These behaviors come for free once every screen has a path.
Deep Links
A deep link opens a specific screen from outside the app, such as a link in an email. Android and iOS need extra setup to claim a web address for your app. The router handles the Flutter side by matching the incoming path against the route list and building the right screen.
Practice Ideas
Build a store app with a home page, a product page at /product/:id, and a login page. Add a redirect that sends visitors to the login page until a login flag turns true. Run the app in Chrome and watch the address bar change as you move between screens.
