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.