How does navigation work in Flutter, and what's the difference between `push` and `pushReplacement`?
Show answer — try answering out loud first
Flutter navigates with a Navigator that manages a stack of routes. push adds a screen on top of the current one (you can go back with pop). pushReplacement replaces the current screen with another (you can't go back to the previous one). There's also declarative navigation (Navigator 2.0 and packages like go_router) for more complex cases.
Think of navigation as a stack of cards: the top card is the screen you see.
push: you put a new card on top.popremoves it and you go back to the previous one.pushReplacement: you swap the top card for another one. The previous one disappears from the stack, so there's no "going back".pushNamed: you navigate using registered route names ('/detail'), handy for centralizing routes.popwith a result: when going back you can return a value to the previous screen.
For apps with complex navigation (deep links, web, navigation state), use the declarative approach with go_router, which is the one currently recommended by the Flutter team.
import 'package:flutter/material.dart';
// Go to a new screen and be able to come back
void openDetail(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const Detail()),
);
}
// Replace the current one (for example, after a login: you don't want to go back to the login)
void goToHome(BuildContext context) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const Home()),
);
}
// Go back returning a result
void goBackWithData(BuildContext context) {
Navigator.of(context).pop("result");
}
class Detail extends StatelessWidget {
const Detail({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
class Home extends StatelessWidget {
const Home({super.key});
@override
Widget build(BuildContext context) => const Scaffold();
}
Using push when you should have used pushReplacement, typically after a login or a splash. If you push to the home after login, the user can press "back" and return to the login screen, which makes no sense. Another mistake: trying to pop when there's nothing left below in the stack (you'd close the app by accident).
"Flutter uses a
Navigatorthat manages a stack of routes.pushadds a screen on top and I can go back withpop;pushReplacementswaps the current screen for another with no way back, which is what I use after a login or a splash. I can navigate by name withpushNamedand return results withpop. For complex navigation, deep links, or web, I use the declarative approach withgo_router, which is the currently recommended one."
After a successful login you want to take the user to the home and make sure the "back" button doesn't return them to the login. Which method do you use?
See answer
pushReplacement (or pushReplacementNamed). It replaces the login screen with the home in the stack, so the login disappears and the "back" button no longer returns to it. If you wanted to clear the entire previous stack (for example, several screens), you'd use pushAndRemoveUntil.