Navigator is a navigation manager widget in Flutter that manages a stack of Route objects for moving between screens using push, pop, pushReplacement, and pushNamed methods. Unlike direct widget replacement via State, Navigator works at the level of entire screens: it stores transition history and supports platform-specific animations. According to the Flutter API Reference (2026), Navigator 2.0 (Router) provides declarative navigation management for complex scenarios with deep links and adaptive design. In a typical application, Navigator ensures correct behavior of the Back button on Android and swipe gestures on iOS.
Key Takeaways
Navigator is a widget that manages a stack of Route objects, implementing screen navigation in a Flutter application. Each call to push places a new Route on top of the stack, pop removes the top Route and returns to the previous screen. MaterialApp automatically creates a Navigator for the entire application, making it accessible via Navigator.of(context).
Unlike StatefulWidget, where content replacement happens via setState inside a single widget, Navigator operates with entire screens that have their own lifecycle. Each Route in the stack is an isolated state with its own BuildContext, preventing memory leaks and simplifying dependency management. When pop is called, the unused Route is destroyed, freeing resources.
According to the Flutter Navigation Guide (2026), Navigator has evolved from an imperative API (Navigator 1.0) to a declarative one (Navigator 2.0). Navigator 1.0 uses push/pop methods directly, which is convenient for simple scenarios. Navigator 2.0 (Router) is suitable for applications with deep links, adaptive navigation, and web routing.
Internally, Navigator uses Overlay — a special widget that displays Routes one on top of another. Each Route creates its own position in the Overlay with a z-index corresponding to its depth in the stack. This explains why when push is called, the new screen animates on top of the previous one, and when pop is called, the previous screen is already ready to display: it was not destroyed but remained in the Overlay below the new one.
For transition animations, Navigator uses PageTransitionsTheme, which can be overridden in ThemeData. Platform-specific animations are set via CupertinoPageRoute for iOS (slide from right) and MaterialPageRoute for Android (slide from bottom). Navigator automatically selects the correct animation when using PlatformRoute.
Navigator provides a set of methods for managing the Route stack. Each method solves a specific navigation task — from a simple transition to a complete replacement of the screen history. Let us review the main methods with usage examples.
| Method | Description | Use Case |
|---|---|---|
| push | Adds a Route to the top of the stack | Navigate to a new screen with the ability to return |
| pop | Removes the top Route from the stack | Return to the previous screen |
| pushReplacement | Replaces the current Route with a new one | After login — the login screen is replaced by the main screen |
| pushAndRemoveUntil | Adds a Route and removes previous ones until a condition is met | Navigate to the main screen with history clearance |
| popUntil | Removes Routes from the stack until a condition is met | Return to a specific screen in the history |
| maybePop | Calls pop only if the stack contains >1 Route | Prevent app closure on accidental back press |
The push method takes a Route and returns a Future with the result passed during pop. This allows receiving data from the screen that was navigated to. For example, a date picker screen can return a DateTime via Navigator.pop(context, selectedDate). The pop method without arguments returns null, with an argument — passes the value to the calling screen.
pushReplacement replaces the current Route with a new one, removing the current route from the stack. This is critical for scenarios where the user should not be able to return to the previous screen. A typical example is the login screen: after successful login, the current screen is replaced by the main screen, and the Back button does not return to the login form.
Navigator supports navigation by named routes via the pushNamed method. Instead of creating a Route directly, the developer specifies a string identifier, and Navigator automatically creates the Route based on the configuration in MaterialApp. This simplifies code and centralizes route definition in one place.
Named routes are defined through the routes property in MaterialApp, where each key is a path string and the value is a function returning a Widget. For dynamic routes (with parameters), onGenerateRoute is used — a callback that receives RouteSettings and returns a Route. This allows passing arguments via the arguments parameter and implementing deep navigation.
According to the Flutter Cookbook (2026), passing arguments via pushNamed is done using the arguments: Object? parameter. The receiving screen extracts arguments via ModalRoute.of(context)!.settings.arguments, providing type-safe data transfer without global variables or InheritedWidget.
The onUnknownRoute property in MaterialApp handles cases where pushNamed is called with a non-existent route. This is useful for showing a 404 screen or redirecting to the home page. In combination with onGenerateRoute, it ensures full coverage of all possible navigation scenarios.
Navigator 2.0 (also known as the Router API) is a declarative approach to navigation introduced in Flutter 2.0. Unlike the imperative Navigator 1.0, where the developer calls push/pop, Router manages navigation through state, automatically synchronizing the browser URL with the current screen. This is especially important for web applications and desktop versions.
The Navigator 2.0 architecture consists of three key components: RouteInformationParser parses the URL into a route configuration, RouterDelegate transforms the configuration into a list of Routes, and BackButtonDispatcher handles the system Back button. This architecture makes navigation fully predictable and testable.
To simplify working with Navigator 2.0, there are wrapper packages: go_router (recommended by Google), auto_route, and beamer. go_router provides a declarative DSL for defining routes with support for nested navigation, redirects, and deep links without manually implementing RouterDelegate. According to pub.dev (2026), go_router is used in 35% of new Flutter projects that prefer a declarative approach.
Consider an example of Navigator with named routes and data passing between screens. The code demonstrates a product list screen, a transition to a detail screen, and returning with a result.
// Route configuration in MaterialApp
MaterialApp(
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
return MaterialPageRoute(
builder: (context) => const ProductListPage(),
);
}
if (settings.name == '/product') {
final productId = settings.arguments as String;
return MaterialPageRoute(
builder: (context) => ProductDetailPage(productId: productId),
);
}
return MaterialPageRoute(
builder: (context) => const NotFoundPage(),
);
},
)
// Navigation with data passing
final result = await Navigator.pushNamed(
context,
'/product',
arguments: 'product_42',
);
// Getting data on the receiving screen
final args = ModalRoute.of(context)!.settings.arguments as String;
// Replace screen after login
Navigator.pushReplacementNamed(context, '/home');
// Clear stack to main screen
Navigator.pushNamedAndRemoveUntil(
context,
'/home',
(route) => false,
);
In the example, Navigator.pushNamed passes the product ID to the detail screen. Upon return via Navigator.pop(context, updatedProduct), the calling screen receives the updated data in the result variable. pushReplacementNamed replaces the current screen after authorization, and pushNamedAndRemoveUntil with the condition (route) => false completely clears the stack, preventing navigation back to previous screens.
Frequently Asked Questions
Navigator 1.0 — an imperative API with push and pop methods, convenient for simple mobile applications. Navigator 2.0 — a declarative API via Router, RouterDelegate, and RouteInformationParser, necessary for web applications with URL routing, deep links, and adaptive navigation. For practical projects, go_router is recommended as a simplified wrapper over Navigator 2.0.
Data is passed via the arguments parameter in pushNamed or directly through the Route constructor. On the receiving screen, data is retrieved via ModalRoute.of(context)!.settings.arguments. To return data, use Navigator.pop(context, result) — the calling screen will receive the result as a Future value returned from push.
This happens if the current screen was opened via pushReplacement, which removes the previous Route from the stack. In this case, there is no navigation history, and the Back button closes the application. To return, use regular push instead of pushReplacement. Also check that the Navigator.pop call is correctly handled on the current screen.
Use pushReplacement to replace the current screen with a new one — the previous screen is removed from the stack and cannot be returned to. For complete history clearance, use pushAndRemoveUntil with the condition (route) => false. Alternatively, you can override WillPopScope (deprecated) or PopScope to intercept the system Back button.
go_router is a declarative navigation package from Google built on top of Navigator 2.0. It provides a simple DSL for defining routes with support for nesting, redirects, deep links, and ShellRoute for BottomNavigationBar. Use go_router for new projects, especially if web support or complex navigation patterns with guarded routes are required.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also