My app needs deep links (https links opening a product page), a login redirect and a bottom nav that keeps each tab's stack. Plain Navigator.push is getting messy. Is go_router the right tool and how do I add an auth redirect?
DEV3 Developer Forum
Should I use go_router or plain Navigator for a Flutter app with deep links and a login guard?
Every post is reviewed first. Usually reviewed within 24 hours.
1 reply
Short answer
Yes. Navigator.push (imperative, Navigator 1.0) is fine for simple apps. As soon as you need URLs, deep links, web support or redirects, use a declarative router. go_router is maintained by the Flutter team and covers all of these.
Basic setup with an auth guard
final router = GoRouter(
initialLocation: '/',
refreshListenable: authNotifier, // a ChangeNotifier that fires on login/logout
redirect: (context, state) {
final loggedIn = authNotifier.isLoggedIn;
final goingToLogin = state.matchedLocation == '/login';
if (!loggedIn && !goingToLogin) return '/login';
if (loggedIn && goingToLogin) return '/';
return null; // no redirect
},
routes: [
GoRoute(path: '/', builder: (_, __) => const HomePage()),
GoRoute(path: '/login', builder: (_, __) => const LoginPage()),
GoRoute(
path: '/product/:id',
builder: (_, state) =>
ProductPage(id: state.pathParameters['id']!),
),
],
);
MaterialApp.router(routerConfig: router);
go vs push
context.go('/product/5')replaces the stack to match that location (web-style).context.push('/product/5')adds on top and returns a Future you can await for a result.
Tabs that keep state
Use StatefulShellRoute.indexedStack with one branch per tab; each branch keeps its own navigation stack and scroll position.
Deep links
Android needs an intent filter (with android:autoVerify for app links) and iOS needs associated domains plus an apple-app-site-association file on your server. The router then receives the path and matches it with no extra code on current Flutter versions.
Pitfalls
- Redirect loops: always return
nullwhen no change is needed. - Forgetting
refreshListenable, so login does not trigger a re-evaluation. - Parameters are strings, parse ints yourself.
A related example: bottom navigation with nested navigators.