Current field guide · 2026
Choose which Navigator owns a page
A root Navigator and a shell Navigator serve different purposes; use keys when a destination must appear above the shell.
On this page
Make ownership explicit
A shell commonly owns its own Navigator. A modal-like detail or full-screen flow may need the root Navigator instead. The page's visual placement follows that ownership, not just how deeply its path is nested.
Keep key relationships valid
Create stable GlobalKey instances outside frequently rebuilt widgets. Attach the root key to the router and a shell key to the appropriate ShellRoute. Set parentNavigatorKey on the route that needs the parent Navigator.
Avoid competing stacks
Mixing arbitrary imperative Navigator calls with declarative locations can make browser history and deep links difficult to reason about. Use an imperative push only when its lifecycle and expected Back behavior are intentional.
Verify the destination in isolation
Open the full-screen route directly, arrive from inside the shell, and leave with Back. Check the visible frame and the retained branch underneath. A screenshot of one entry path is not enough to validate the navigation model.
final rootKey = GlobalKey<NavigatorState>();
final shellKey = GlobalKey<NavigatorState>();
// Attach rootKey to GoRouter.navigatorKey.
// Attach shellKey to ShellRoute.navigatorKey.
GoRoute(
path: 'details',
parentNavigatorKey: rootKey,
builder: (_, __) => const FullScreenDetails(),
)Sources & version context
GoRouter.dev documentation edition. Examples illustrate the APIs described in the linked primary documentation. Adapt application-owned widgets and services to your project. They are not an executed Flutter session in this browser.