Learn
How a navigation request reaches Flutter
See the five objects in a working request, where each one is created, and which object your feature code actually uses.
How a navigation request reaches Flutter
Consider a catalog page that opens Product and expects a purchase result:
final NavigationTicket<bool> ticket = context.readNavigation.push<bool>(
const ProductDestination('keyboard-42'),
);
Five objects take part. Only the first and last normally appear in feature UI code.
| Object | What it does | Where you create it |
|---|---|---|
ProductDestination | Carries typed intent and parameters | Feature/domain-facing code |
productRoute | Builds ProductPage and maps the Destination to a URI | Feature navigation module |
NavigationGraph | Combines routes, modules, scopes, and policies | Application startup code |
NavigationSession | Owns the mutable stacks and Flutter Router objects | Root StatefulWidget |
NavigationPort | Exposes exact operations to application code | Read from context or inject as an interface |
The request path
For the call above, Ark Navigation:
- finds the Route Definition that accepts
ProductDestination; - selects its Module, Mount, and Navigator Scope;
- applies Redirects;
- checks leave and enter Guards;
- commits one new immutable Snapshot;
- asks Flutter Router to render the new page;
- completes
ticket.committed; - later completes
ticket.completedwhen Product is popped or removed.
No page is inserted before policy checks finish.
The owner you must not forget
Create one Session for one Flutter view and dispose it with that view:
final class AppHostState extends State<AppHost> {
late final NavigationSession navigation = NavigationSession(
id: const NavigationSessionId('main-window'),
graph: createAppGraph(),
);
@override
Widget build(BuildContext context) => MaterialApp.router(
routerConfig: navigation.routerConfig,
);
@override
void dispose() {
navigation.dispose();
super.dispose();
}
}
Do not create the Session in build(). That would replace Navigator keys, browser-history state, stacks, and pending result tickets on a rebuild.
What feature code should depend on
In a widget callback:
context.readNavigation.push<void>(const SettingsDestination());
In a Presenter or application service, accept NavigationPort through the constructor. Do not store BuildContext there:
final class CheckoutPresenter {
CheckoutPresenter(this.navigation);
final NavigationPort navigation;
void showReceipt(String orderId) {
navigation.replaceTop<void>(ReceiptDestination(orderId));
}
}
Use NavigationController only for infrastructure tasks such as restoration or Graph updates. Regular features need the smaller NavigationPort.