Announcing Jetpack Navigation 3
Posted by Don Turner - Developer Relations Engineer Navigating between screens in your app should be simple, shouldn't it? However, building a robust, scalable, and delightful navigation experience can be a challenge. For years, the Jetpack Navigation library has been a key tool for developers, but as the Android UI landscape has evolved, particularly with the rise of Jetpack Compose, we recognized the need for a new approach. Today, we're excited to introduce Jetpack Navigation 3, a new navigation library built from the ground up specifically for Compose. For brevity, we'll just call it Nav3 from now on. This library embraces the declarative programming model and Compose state as fundamental building blocks. Why a new navigation library? The original Jetpack Navigation library (sometimes referred to as Nav2 as it's on major version 2) was initially announced back in 2018, before AndroidX and before Compose. While it served its original goals well, we heard from you that it had several limitations when working with modern Compose patterns. One key limitation was that the back stack state could only be observed indirectly. This meant there could be two sources of truth, potentially leading to an inconsistent application state. Also, Nav2's NavHost was designed to display only a single destination – the topmost one on the back stack – filling the available space. This made it difficult to implement adaptive layouts that display multiple panes of content simultaneously, such as a list-detail layout on large screens. Figure 1. Changing from single pane to multi-pane layouts can create navigational challenges Founding principles Nav3 is built upon principles designed to provide greater flexibility and developer control: You own the back stack: You, the developer, not the library, own and control the back stack. It's a simple list which is backed by Compose state. Specifically, Nav3 expects your back stack to be SnapshotStateList where T can be any type you choose. You can navigate by adding or removing items (Ts), and state changes are observed and reflected by Nav3's UI. Get out of your way: We heard that you don't like a navigation library to be a black box with inaccessible internal components and state. Nav3 is designed to be open and extensible, providing you with building blocks and helpful defaults. If you want custom navigation behavior you can drop down to lower layers and create your own components and customizations. Pick your building blocks: Instead of embedding all behavior within the library, Nav3 offers smaller components that you can combine to create more complex functionality. We've also provided a "recipes book" that shows how to combine components to solve common navigation challenges. Figure 2. The Nav3 display observes changes to the developer-owned back stack. Key features Animations: Built-in transition animations are provided for changes in destination, including for predictive back. It also has a flexible API for custom animation behavior, allowing animations to be overridden at both the app and the individual screen level. Adaptive layouts: A flexible layout API (named Scenes) allows you to render multiple destinations in the same layout (for example, a list-detail layout on large screen devices). This makes it easy to switch between single and multi-pane layouts. State scoping: Enables state to be scoped to destinations on the back stack, including optional ViewModel support via a dedicated Jetpack lifecycle library. Modularity: The API design allows navigation code to be split across multiple modules. This improves build times and allows clear separation of responsibilities between feature modules. Figure 3. Custom animations and predictive back are easy to implement, and easy to override for individual destinations. Basic code example To give you an idea of how Nav3 works, here's a short code sample. // Define the routes in your app and any arguments. data object Home data class Product(val id: String) // Create a back stack, specifying the route the app should start with. val backStack = remember { mutableStateListOf(ProductList) } // A NavDisplay displays your back stack. Whenever the back stack changes, the display updates. NavDisplay( backStack = backStack, // Specify what should happen when the user goes back onBack = { backStack.removeLastOrNull() }, // An entry provider converts a route into a NavEntry which contains the content for that route. entryProvider = { route -> when (route) { is Home -> NavEntry(route) { Column { Text("Welcome to Nav3") Button(onClick = { // To navigate to a new route, just add that route to the back stack backStack.add(Product("123")) }) { Text("Click to navigate") } }



Navigating between screens in your app should be simple, shouldn't it? However, building a robust, scalable, and delightful navigation experience can be a challenge. For years, the Jetpack Navigation library has been a key tool for developers, but as the Android UI landscape has evolved, particularly with the rise of Jetpack Compose, we recognized the need for a new approach.
Today, we're excited to introduce Jetpack Navigation 3, a new navigation library built from the ground up specifically for Compose. For brevity, we'll just call it Nav3 from now on. This library embraces the declarative programming model and Compose state as fundamental building blocks.
Why a new navigation library?
The original Jetpack Navigation library (sometimes referred to as Nav2 as it's on major version 2) was initially announced back in 2018, before AndroidX and before Compose. While it served its original goals well, we heard from you that it had several limitations when working with modern Compose patterns.
One key limitation was that the back stack state could only be observed indirectly. This meant there could be two sources of truth, potentially leading to an inconsistent application state. Also, Nav2's NavHost was designed to display only a single destination – the topmost one on the back stack – filling the available space. This made it difficult to implement adaptive layouts that display multiple panes of content simultaneously, such as a list-detail layout on large screens.
Founding principles
Nav3 is built upon principles designed to provide greater flexibility and developer control:
- You own the back stack: You, the developer, not the library, own and control the back stack. It's a simple list which is backed by Compose state. Specifically, Nav3 expects your back stack to be SnapshotStateList
where T can be any type you choose. You can navigate by adding or removing items (Ts), and state changes are observed and reflected by Nav3's UI. - Get out of your way: We heard that you don't like a navigation library to be a black box with inaccessible internal components and state. Nav3 is designed to be open and extensible, providing you with building blocks and helpful defaults. If you want custom navigation behavior you can drop down to lower layers and create your own components and customizations.
- Pick your building blocks: Instead of embedding all behavior within the library, Nav3 offers smaller components that you can combine to create more complex functionality. We've also provided a "recipes book" that shows how to combine components to solve common navigation challenges.

Key features
- Animations: Built-in transition animations are provided for changes in destination, including for predictive back. It also has a flexible API for custom animation behavior, allowing animations to be overridden at both the app and the individual screen level.
- Adaptive layouts: A flexible layout API (named Scenes) allows you to render multiple destinations in the same layout (for example, a list-detail layout on large screen devices). This makes it easy to switch between single and multi-pane layouts.
- State scoping: Enables state to be scoped to destinations on the back stack, including optional ViewModel support via a dedicated Jetpack lifecycle library.
- Modularity: The API design allows navigation code to be split across multiple modules. This improves build times and allows clear separation of responsibilities between feature modules.
- common navigation UI, such as a navigation rail or bar
- conditional navigation, such as a login flow
- custom layouts using Scenes

Basic code example
To give you an idea of how Nav3 works, here's a short code sample.
// Define the routes in your app and any arguments. data object Home data class Product(val id: String) // Create a back stack, specifying the route the app should start with. val backStack = remember { mutableStateListOf(ProductList) } // A NavDisplay displays your back stack. Whenever the back stack changes, the display updates. NavDisplay( backStack = backStack, // Specify what should happen when the user goes back onBack = { backStack.removeLastOrNull() }, // An entry provider converts a route into a NavEntry which contains the content for that route. entryProvider = { route -> when (route) { is Home -> NavEntry(route) { Column { Text("Welcome to Nav3") Button(onClick = { // To navigate to a new route, just add that route to the back stack backStack.add(Product("123")) }) { Text("Click to navigate") } } } is Product -> NavEntry(route) { Text("Product ${route.id} ") } else -> NavEntry(Unit) { Text("Unknown route: $route") } } } )
Get started and provide feedback
To get started, check out the developer documentation, plus the recipes repository which provides examples for:
We plan to provide code recipes, documentation and blogs for more complex use cases in future.
Nav3 is currently in alpha, which means that the API is liable to change based on feedback. If you have any issues, or would like to provide feedback, please file an issue.
Nav3 offers a flexible and powerful foundation for building modern navigation in your Compose applications. We're really excited to see what you build with it.
Explore this announcement and all Google I/O 2025 updates on io.google starting May 22.