Navigation in Compose

Most apps have more than one screen. Navigation-Compose lets you define screens as routes , move between them with a NavController , and get a managed back stack for free.

Learn Navigation in Compose in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end you'll set up a NavHost , declare composable routes, navigate between them, and pass arguments along the route.

What You'll Learn in This Lesson

1️⃣ NavController, NavHost, and Routes

Create a controller with rememberNavController() , then declare your graph in a NavHost . Each composable(route) maps a route string to a screen.

navController.navigate("details") pushes the Details destination; the system Back button pops it.

2️⃣ Passing Arguments

Declare a placeholder with curly braces in the route — profile/{' '} — list it in arguments , then read it from the destination's backStackEntry.arguments .

Your turn. Replace the TODO , then run and compare.

Add a second destination and navigate to it from a button, then return with Back.

📋 Quick Reference — Navigation

Practice quiz

Which object drives navigation between Compose destinations?

  • NavManager
  • NavController
  • Router
  • ScreenStack

Answer: NavController. The NavController manages the back stack and performs navigate() calls.

Which composable defines the navigation graph?

  • NavGraph
  • NavHost
  • Router
  • ScreenHost

Answer: NavHost. NavHost hosts the graph, mapping routes to composable destinations.

How do you create a NavController in Compose?

  • NavController()
  • remember { NavController() }
  • rememberNavController()
  • getNavController()

Answer: rememberNavController(). rememberNavController() creates and remembers a NavHostController for Compose.

Inside a NavHost, how do you declare a destination?

  • composable("home") { HomeScreen() }
  • screen("home")
  • route("home")
  • destination("home")

Answer: composable("home") { HomeScreen() }. The composable(route) { } builder maps a route string to a screen composable.

What does navController.navigate("details") do?

  • Closes the app
  • Navigates to the 'details' destination, pushing it on the back stack
  • Deletes the route
  • Reloads the current screen

Answer: Navigates to the 'details' destination, pushing it on the back stack. navigate(route) moves to that destination and adds it to the back stack.

How is a route argument declared in a route string?

  • details:{id}
  • details/<id>
  • details/{id}
  • details?id

Answer: details/{id}. Curly braces mark a path argument placeholder, e.g. details/{id}.

How do you read a String argument inside the destination?

  • backStackEntry.arguments?.getString("id")
  • args.id
  • navController.get("id")
  • intent.getStringExtra("id")

Answer: backStackEntry.arguments?.getString("id"). The NavBackStackEntry's arguments Bundle holds the parsed route arguments.

What parameter sets the first screen shown by a NavHost?

  • firstRoute
  • home
  • startDestination
  • initial

Answer: startDestination. NavHost(navController, startDestination = "home") sets the initial destination.

To pass an argument when navigating, you typically build the route how?

  • navigate("details", id)
  • navigate("details/\$id")
  • navigate("details").with(id)
  • navigate { id }

Answer: navigate("details/\$id"). You interpolate the value into the route string, e.g. navigate("details/42").

Why use string routes and a NavHost instead of manually swapping composables?

  • It is required by Kotlin
  • It removes the need for state
  • It is the only way to show text
  • It gives a managed back stack, deep links, and argument handling

Answer: It gives a managed back stack, deep links, and argument handling. Navigation-Compose provides a real back stack, type-safe-ish routing, deep links, and arguments.