100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Kotlin

Nested Navigation and the Back Stack

How to group related destinations into nested navigation graphs, control back stack behavior with popUpTo, and manage multi-flow apps cleanly.

NavigationIntermediate10 min readJul 8, 2026
Analogies

Nested Navigation and the Back Stack

As an app grows past a handful of screens, a single flat list of destinations inside one NavHost becomes hard to reason about — an onboarding flow, a checkout flow, and the main app tabs are conceptually separate journeys that happen to share the same NavController. Nested navigation graphs let you group related destinations together as a self-contained sub-graph with its own start destination, while still living inside the same overall back stack managed by one NavController.

🏏

Cricket analogy: A flat NavHost for a growing app is like running a whole cricket board's fixtures, domestic league, international tour, and youth academy, off one undifferentiated calendar instead of separate, self-contained tournament structures under one governing body.

A nested graph is declared with navigation(startDestination = ..., route = "auth") { ... } inside the NavHost builder, containing its own composable() entries for login, signup, and forgot-password screens, for example. From the outside, the entire nested graph is reachable by navigating to its route ("auth"), and internally its screens navigate among themselves using the same NavController, unaware that they're nested.

🏏

Cricket analogy: A nested graph declared with route 'auth' is like a qualifying tournament bracket nested inside the larger world cup structure, teams navigate among their own qualifier matches, unaware they're just one sub-bracket of the bigger event.

kotlin
NavHost(navController = navController, startDestination = "main") {
    navigation(startDestination = "login", route = "auth") {
        composable("login") {
            LoginScreen(
                onLoginSuccess = {
                    navController.navigate("main") {
                        popUpTo("auth") { inclusive = true }
                    }
                },
                onSignUp = { navController.navigate("signup") }
            )
        }
        composable("signup") {
            SignUpScreen(onBack = { navController.popBackStack() })
        }
    }

    composable("main") {
        MainScreen()
    }
}

Controlling the back stack with popUpTo

The example above uses popUpTo("auth") { inclusive = true } when navigating from login success to the main screen. Without it, a successful login would simply push 'main' on top of the auth flow's back stack entries, meaning pressing the system back button from 'main' would return the user to the login screen — clearly wrong once authenticated. popUpTo with inclusive = true clears every entry up to and including the auth graph's start, so main becomes the new base of the stack and there's nothing to 'go back' to.

🏏

Cricket analogy: popUpTo with inclusive true after login is like a team being promoted out of the qualifying rounds entirely, once you're in the main draw, there's no 'back button' to the qualifiers because that bracket was cleared from the tournament path.

Nested graph ViewModel scoping

One major benefit of nested graphs beyond visual organization is ViewModel scoping: a ViewModel obtained with hiltViewModel() inside a screen that specifies the nested graph's route as its viewModelStoreOwner is shared by every screen inside that graph and is cleared automatically when the entire graph is popped off the back stack. This is exactly the mechanism used to share, for example, sign-up form state across a multi-step signup flow without a global singleton.

🏏

Cricket analogy: ViewModel scoping to a nested graph is like a specific tour's team management staff, coach, physio, analyst, shared by every match in that tour and dismissed automatically once the tour ends, rather than a permanent board-wide staff.

Think of a nested graph as a 'chapter' within a book (the whole back stack). Screens within a chapter can flip back and forth freely, but popUpTo with inclusive = true is like tearing out the entire chapter once it's done, so the reader can't accidentally flip back into it.

A common bug is forgetting inclusive = true (or forgetting popUpTo entirely) after a flow like login or onboarding completes, leaving stale screens on the back stack that the user can navigate back into after the flow is 'done' — e.g. pressing back after login re-shows the login screen.

saveState and restoreState for tab-like navigation

When switching between top-level destinations (like bottom navigation tabs), popUpTo(startRoute) { saveState = true } combined with launchSingleTop = true and restoreState = true on the navigate call preserves each tab's own back stack and scroll position when switching away and back, rather than resetting the tab to its start destination every time it's revisited.

🏏

Cricket analogy: Preserving each tab's back stack with saveState and restoreState is like a multi-format player keeping their Test technique intact even after playing a T20 innings, switching formats doesn't reset their form back to zero each time.

  • Nested graphs group related destinations (e.g. an auth or checkout flow) under a single route while sharing one overall NavController.
  • navigation(startDestination, route) declares a sub-graph inside the NavHost builder.
  • popUpTo with inclusive = true removes back stack entries up to and including a given destination, preventing 'back' from re-entering a completed flow.
  • ViewModels scoped to a nested graph's route are shared across its screens and cleared when the graph is popped.
  • Forgetting popUpTo after a completed flow is a common bug that leaves stale screens reachable via back.
  • saveState/restoreState with launchSingleTop preserves each tab's back stack when navigating between top-level tab destinations.

Practice what you learned

Was this page helpful?

Topics covered

#Kotlin#AndroidWithJetpackComposeStudyNotes#MobileDevelopment#NestedNavigationAndTheBackStack#Nested#Navigation#Back#Stack#DataStructures#StudyNotes#SkillVeris