30 KiB
Navigation Compose 3: Research Report
Compiled 2026-04-03. Sources: Android Developer docs, JetBrains Kotlin docs, nav3-recipes repo, Android Developers Blog, community blog posts, and release notes.
Table of Contents
- Overview
- Core Concepts & API
- Best Practices
- Migration Guide (Nav 2 → Nav 3)
- Gotchas, Footguns & Complications
- KMP / Compose Multiplatform Considerations
- Appendix: Version & Dependency Reference
1. Overview
What is Navigation 3?
Navigation 3 (Nav3) is a ground-up rewrite of Android's Jetpack Navigation, designed specifically for Jetpack Compose. Released as stable 1.0.0 on November 19, 2025, it replaces the controller-based paradigm of Nav 2 with a state-based, declarative approach where the developer owns the back stack directly.
- Stable release: 1.0.1 (Feb 11, 2026)
- Latest: 1.1.0-rc01 (Mar 25, 2026)
- Min SDK: 23
- Compile SDK: 36+
How It Differs from Nav 2
| Aspect | Nav 2 | Nav 3 |
|---|---|---|
| State ownership | Library-owned (NavController) |
Developer-owned (SnapshotStateList) |
| Back stack model | Hidden internal structure | Transparent mutable list |
| Navigation API | navController.navigate() |
backStack.add(key) |
| Host component | NavHost |
NavDisplay |
| Route definition | composable<T> { } in NavHost |
entry<T> { } in entryProvider |
| Layout flexibility | Single pane only | Multi-pane via Scenes API |
| Nested graphs | navigation<T> { } |
Not needed — flat entry list |
| Design philosophy | Opinionated framework | Flexible building blocks |
| Compose alignment | Bolted-on Compose support | Compose-first from scratch |
Founding Principles
- You Own the Back Stack — Navigation state is a
SnapshotStateList<T>you control directly. Push =add(), pop =removeLastOrNull(). - Get Out of Your Way — The library provides open, extensible building blocks rather than a black box.
- Pick Your Building Blocks — Composable components you combine for your specific needs, with recipes for complex scenarios.
Data Flow
User Action → modify backStack (add/remove) → NavDisplay observes change → entryProvider resolves key → NavEntry.content rendered
This follows Unidirectional Data Flow (UDF), fully aligned with Compose's declarative model.
2. Core Concepts & API
2.1 Keys (Routes)
Routes in Nav 3 are simple Kotlin data types that implement NavKey:
@Serializable
data object Home : NavKey
@Serializable
data class ProductDetail(val id: String) : NavKey
@Serializable
data object Settings : NavKey
Keys must be:
@Serializable(for state persistence)- Implement
NavKey(marker interface forrememberNavBackStack)
2.2 Back Stack
The back stack is a SnapshotStateList<T> — you own it completely:
// Simple (no persistence across process death)
val backStack = remember { mutableStateListOf<Any>(Home) }
// Persistent (survives config changes + process death)
val backStack = rememberNavBackStack(Home)
Navigation is just list manipulation:
// Navigate forward
backStack.add(ProductDetail(id = "123"))
// Navigate back
backStack.removeLastOrNull()
2.3 NavEntry
NavEntry wraps a composable function with its key and optional metadata:
NavEntry(
key = ProductDetail("123"),
metadata = mapOf("type" to "detail")
) {
ProductDetailScreen()
}
2.4 Entry Provider
Resolves keys to NavEntry objects. Two approaches:
Lambda function:
entryProvider = { key ->
when (key) {
is Home -> NavEntry(key) { HomeScreen() }
is ProductDetail -> NavEntry(key) { ProductDetailScreen(key.id) }
else -> NavEntry(Unit) { Text("Unknown") }
}
}
DSL (recommended):
entryProvider = entryProvider {
entry<Home> { HomeScreen() }
entry<ProductDetail> { key -> ProductDetailScreen(key.id) }
}
2.5 NavDisplay
The primary UI component that observes the back stack and renders content:
NavDisplay(
backStack = backStack,
onBack = { backStack.removeLastOrNull() },
entryDecorators = listOf(
rememberSaveableStateHolderNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator()
),
sceneStrategies = listOf(DialogSceneStrategy()),
entryProvider = entryProvider {
entry<Home> { HomeScreen() }
entry<ProductDetail> { key -> ProductDetailScreen(key.id) }
}
)
2.6 NavEntry Decorators
Decorators wrap each NavEntry with additional logic (state holders, ViewModel stores, logging):
| Decorator | Purpose |
|---|---|
rememberSaveableStateHolderNavEntryDecorator() |
Persists rememberSaveable state across config changes and process death. Should be first in the list. |
rememberViewModelStoreNavEntryDecorator() |
Scopes ViewModels to individual NavEntry lifecycle. Requires androidx.lifecycle:lifecycle-viewmodel-navigation3 dependency. |
rememberSharedViewModelStoreNavEntryDecorator() |
Enables ViewModel sharing between parent/child entries. |
Custom decorator example:
class LoggingDecorator<T : Any> : NavEntryDecorator<T>(
decorate = { entry ->
Log.d("Nav", "Entered ${entry.contentKey}")
entry.Content()
},
onPop = { key -> Log.d("Nav", "Popped $key") }
)
2.7 Scenes & SceneStrategy
Scenes render one or more NavEntry instances. SceneStrategies determine which Scene to use based on the current entries.
Built-in strategies:
SinglePaneSceneStrategy— Default, shows topmost entryDialogSceneStrategy— Renders entries with dialog metadata as overlaysListDetailSceneStrategy(frommaterial3-adaptive-navigation3) — Adaptive list-detail layout
Custom strategy example (list-detail):
class ListDetailSceneStrategy<T : Any>(
val windowSizeClass: WindowSizeClass
) : SceneStrategy<T> {
override fun SceneStrategyScope<T>.calculateScene(
entries: List<NavEntry<T>>
): Scene<T>? {
if (!windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND))
return null
val detailEntry = entries.lastOrNull()?.takeIf { it.metadata.contains(DetailKey) } ?: return null
val listEntry = entries.findLast { it.metadata.contains(ListKey) } ?: return null
return ListDetailScene(
key = listEntry.contentKey,
previousEntries = entries.dropLast(1),
listEntry = listEntry,
detailEntry = detailEntry
)
}
}
2.8 Metadata
Arbitrary Map<String, Any> attached to NavEntry or Scene for communication between components:
// Type-safe metadata DSL (1.1.0-beta01+)
entry<Home>(
metadata = metadata {
put(NavDisplay.TransitionKey) { fadeIn() togetherWith fadeOut() }
put(ListDetailSceneStrategy.ListKey, true)
}
) { HomeScreen() }
2.9 Animations
NavDisplay supports built-in transition animations:
NavDisplay(
backStack = backStack,
// Global defaults
transitionSpec = {
slideInHorizontally(initialOffsetX = { it }) togetherWith
slideOutHorizontally(targetOffsetX = { -it })
},
popTransitionSpec = {
slideInHorizontally(initialOffsetX = { -it }) togetherWith
slideOutHorizontally(targetOffsetX = { it })
},
predictivePopTransitionSpec = {
slideInHorizontally(initialOffsetX = { -it }) togetherWith
slideOutHorizontally(targetOffsetX = { it })
},
entryProvider = entryProvider {
// Per-entry override via metadata
entry<ScreenC>(
metadata = metadata {
put(NavDisplay.TransitionKey) {
slideInVertically(initialOffsetY = { it }) togetherWith
ExitTransition.KeepUntilTransitionsFinished
}
}
) { ScreenC() }
}
)
Shared element transitions:
SharedTransitionLayout {
NavDisplay(
sharedTransitionScope = this,
// ...
)
}
2.10 Deep Linking
Nav 3 does not have built-in deep link support like Nav 2. Instead, you parse intents manually:
- Define
DeepLinkPatternobjects mapping URIs toNavKeyclasses - Parse incoming
Intent.datainto aDeepLinkRequest - Match against patterns to produce a
NavKey - Build a synthetic back stack for proper Up navigation
override fun onCreate(savedInstanceState: Bundle?) {
val uri: Uri? = intent.data
val key: NavKey = uri?.let { parseDeepLink(it) } ?: HomeKey
setContent {
val backStack = rememberNavBackStack(key)
NavDisplay(backStack = backStack, ...)
}
}
Recipes available: Basic deep links, Advanced deep links.
3. Best Practices
3.1 Architecture Pattern
Recommended: Navigator + NavigationState pattern (from official migration guide):
// NavigationState — holds all navigation state
class NavigationState(
val startRoute: NavKey,
topLevelRoute: MutableState<NavKey>,
val backStacks: Map<NavKey, NavBackStack<NavKey>>
) {
var topLevelRoute: NavKey by topLevelRoute
}
// Navigator — handles navigation events
class Navigator(val state: NavigationState) {
fun navigate(route: NavKey) {
if (route in state.backStacks.keys) {
state.topLevelRoute = route
} else {
state.backStacks[state.topLevelRoute]?.add(route)
}
}
fun goBack() { /* ... */ }
}
3.2 Multi-Module Navigation
Nav 3 is designed for modular navigation. Each feature module exposes:
apimodule: Navigation keys (routes)implmodule: Entry builders (content)
// feature/chat/impl
fun EntryProviderScope<NavKey>.chatEntryBuilder() {
entry<ChatRoute> { key -> ChatScreen(key.conversationId) }
entry<ChatSettings> { ChatSettingsScreen() }
}
// app module
NavDisplay(
entryProvider = entryProvider {
chatEntryBuilder()
authEntryBuilder()
settingsEntryBuilder()
}
)
With Koin DI (from nav3-recipes):
// Each feature module provides its entry builder
val chatNavigationModule = module {
factory<EntryProviderScope<NavKey>.() -> Unit>(named("chat")) {
{ chatEntryBuilder(get()) }
}
}
// App module collects all builders
val entryBuilders: List<EntryProviderScope<NavKey>.() -> Unit> = getAll()
NavDisplay(
entryProvider = entryProvider {
entryBuilders.forEach { builder -> this.builder() }
}
)
3.3 ViewModel Scoping
ViewModels are scoped to NavEntry lifecycle via decorators:
NavDisplay(
entryDecorators = listOf(
rememberSaveableStateHolderNavEntryDecorator(), // Always first
rememberViewModelStoreNavEntryDecorator()
),
// ...
)
With this setup:
viewModel()calls inside NavEntry content are scoped to that entry- ViewModels survive config changes
- ViewModels are cleared when the entry is popped
With Koin:
entry<ChatRoute> { key ->
val viewModel = koinViewModel<ChatViewModel>()
ChatScreen(viewModel)
}
3.4 Multiple Back Stacks (Bottom Navigation)
For apps with bottom navigation / top-level routes:
val topLevelRoutes = setOf(Home, Search, Profile)
// Each top-level route gets its own persistent back stack
val backStacks = topLevelRoutes.associateWith { rememberNavBackStack(it) }
// Switch between stacks (state is retained)
var currentTopLevel by remember { mutableStateOf(Home) }
Recipe: Multiple back stacks
3.5 Adaptive / Multi-Pane Layouts
Use Material 3 Adaptive for responsive list-detail:
val listDetailStrategy = rememberListDetailSceneStrategy<NavKey>()
NavDisplay(
backStack = backStack,
sceneStrategies = listOf(listDetailStrategy),
entryProvider = entryProvider {
entry<ConversationList>(
metadata = ListDetailSceneStrategy.listPane(
detailPlaceholder = { Text("Select a conversation") }
)
) { ConversationListScreen() }
entry<ConversationDetail>(
metadata = ListDetailSceneStrategy.detailPane()
) { key -> ConversationDetailScreen(key.id) }
}
)
3.6 Testing Navigation
Nav 3 has no dedicated testing library like Nav 2's navigation-testing. However, since navigation state is just a list, testing is simpler:
@Test
fun testNavigation() {
val backStack = mutableStateListOf<NavKey>(Home)
// Simulate navigation
backStack.add(ProductDetail("123"))
assertEquals(ProductDetail("123"), backStack.last())
// Simulate back
backStack.removeLastOrNull()
assertEquals(Home, backStack.last())
}
For UI testing, you can use standard Compose testing:
@Test
fun testNavigationUI() {
composeTestRule.setContent {
val backStack = remember { mutableStateListOf<NavKey>(Home) }
NavDisplay(
backStack = backStack,
entryProvider = entryProvider { /* ... */ }
)
}
// Assert on rendered content
}
The SceneStrategyScope has a no-arg public constructor specifically for testing (added in 1.0.0-beta01).
4. Migration Guide (Nav 2 → Nav 3)
4.1 Prerequisites
compileSdk36+minSdk23+- All destinations must be composable functions
- Routes must implement
NavKey
4.2 Can Nav 2 and Nav 3 Coexist?
Yes. The official migration guide mentions atomic migration as the recommended approach, but community sources confirm incremental migration is possible:
- Nav 2 and Nav 3 can operate simultaneously during migration
- Features can be migrated one at a time
- Business logic and ViewModels don't need rewriting
However, the official migration guide assumes atomic migration. For incremental, you'd maintain a Nav 2 NavHost for unmigrated features and a Nav 3 NavDisplay for migrated ones, coordinating between them.
4.3 Step-by-Step Migration
Step 1: Add Dependencies
[versions]
nav3Core = "1.0.1"
lifecycleViewmodelNav3 = "2.11.0-alpha03"
[libraries]
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }
androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" }
Step 2: Update Routes to Implement NavKey
// Before
@Serializable data object Home
@Serializable data class Chat(val conversationId: String)
// After
@Serializable data object Home : NavKey
@Serializable data class Chat(val conversationId: String) : NavKey
Step 3: Create NavigationState & Navigator
See Section 3.1 for the full pattern.
Step 4: Replace NavController Calls
| Nav 2 | Nav 3 |
|---|---|
navController.navigate(route) |
navigator.navigate(route) or backStack.add(route) |
navController.popBackStack() |
navigator.goBack() or backStack.removeLastOrNull() |
navController.currentDestination |
backStack.last() |
currentBackStackEntryAsState() |
Direct state observation of backStack |
destination.isRouteInHierarchy() |
key == navigationState.topLevelRoute |
Step 5: Convert Destinations
| Nav 2 | Nav 3 |
|---|---|
composable<T> { } |
entry<T> { } |
dialog<T> { } |
entry<T>(metadata = DialogSceneStrategy.dialog()) { } |
navigation<T>(startDestination = ...) { } |
Delete — replace references with first child route |
NavGraphBuilder extension |
EntryProviderScope<NavKey> extension |
entry.toRoute<T>() |
key parameter: entry<T> { key -> ... } |
Before:
NavHost(navController = navController, startDestination = Home) {
composable<Home> { HomeScreen() }
composable<Chat> { entry ->
val route = entry.toRoute<Chat>()
ChatScreen(route.conversationId)
}
dialog<ConfirmDialog> { ConfirmDialogScreen() }
}
After:
NavDisplay(
backStack = backStack,
onBack = { backStack.removeLastOrNull() },
sceneStrategies = listOf(DialogSceneStrategy()),
entryDecorators = listOf(
rememberSaveableStateHolderNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator()
),
entryProvider = entryProvider {
entry<Home> { HomeScreen() }
entry<Chat> { key -> ChatScreen(key.conversationId) }
entry<ConfirmDialog>(
metadata = DialogSceneStrategy.dialog()
) { ConfirmDialogScreen() }
}
)
Step 6: Remove Nav 2 Dependencies
Remove all Nav 2 imports, NavController, NavHost, NavGraphBuilder, and gradle dependencies.
4.4 Key Differences to Watch
- No NavController — State is a mutable list, not a controller object
- No nested graphs — Delete
navigation<T>blocks entirely - No built-in deep links — Must implement manually (see recipes)
- Route args via key param —
entry<T> { key -> ... }instead oftoRoute<T>() - Dialogs via metadata —
DialogSceneStrategy.dialog()metadata instead ofdialog<T> - Use
rememberSerializable, notrememberSaveable— For top-level route persistence - Decorators are explicit — Must add state/ViewModel decorators manually
5. Gotchas, Footguns & Complications
5.1 Known Issues (from release notes)
| Issue | Status | Versions |
|---|---|---|
| z-order bug during animation interruptions (b/459419800) | Fixed in 1.1.0-rc01 | |
| Lifecycle not capped at STARTED for entries under overlays (b/483966071) | Fixed in 1.1.0-rc01 | |
| Crash with SharedTransitionLayout + OverlayScene (b/478664101) | Fixed in 1.1.0-alpha04 | |
| IllegalStateException in Android Studio Previews (b/477149762) | Fixed in 1.0.1 / NavigationEvent 1.0.2 | |
| Infinite scene recalculation (b/418153031) | Fixed in 1.0.0-alpha07 | |
| Screen flicker when swapping backStack with animations (b/450967248) | Fixed in 1.0.0-beta01 |
5.2 Footguns
-
Decorator order matters —
rememberSaveableStateHolderNavEntryDecorator()must be first in the decorators list. Otherwise,rememberSaveablewon't work inside NavEntry content. -
Animations in adaptive layouts — When using
ListDetailSceneStrategyin two-pane mode (>=600dp), transition animations between top-level destinations may not work. The screen "jumps" without animation. -
No built-in deep link handling — Unlike Nav 2's
deepLinks { }DSL, you must parse intents and build synthetic back stacks yourself. See the recipes repo for patterns. -
rememberNavBackStackrequires NavKey — If you want persistence across process death, all keys must implementNavKeyand be@Serializable. Simpledata objectwithoutNavKeywill work but won't survive process death. -
compileSdk 36 required — This is a hard requirement. If your project is on an older compileSdk, you must upgrade.
-
No nested navigation (>1 level) — The migration guide explicitly states: only one level of nesting is supported. Shared destinations (screens moving between different back stacks) are also unsupported.
-
calculateSceneis no longer@Composable(since 1.0.0-alpha11) — Custom SceneStrategies cannot call composable functions incalculateScene. Userememberin a factory function instead. -
NavBackStack serialization is Android-only — The built-in
NavBackStackSerializeris restricted to Android (b/420443609). For KMP, you need polymorphic serialization (see Section 6). -
API churn in 1.1.x — The 1.1 branch is still in RC. APIs like
SceneStrategyreceivingList<SceneStrategy>instead of chained strategies changed in alpha05. Pin to 1.0.1 for stability.
5.3 Things Harder in Nav 3
- Deep linking: Significantly more manual work required
- Bottom sheet destinations: No built-in support; recipe available but requires custom SceneStrategy
- Fragment/View interop: Must use Views-in-Compose wrappers; Nav 3 is Compose-only
- Shared destinations between back stacks: Not supported
- Testing: No dedicated testing artifact; testing is easier conceptually (just a list) but lacks the convenience APIs of
TestNavHostController
5.4 Things Easier in Nav 3
- Back stack inspection: It's just a list — fully observable and debuggable
- Multi-pane/adaptive layouts: First-class support via Scenes
- Custom navigation logic: No fighting the NavController
- State management: Aligns perfectly with Compose state
- ViewModel scoping: Explicit, clear, and configurable via decorators
6. KMP / Compose Multiplatform Considerations
6.1 Is Nav 3 Available for Compose Multiplatform?
Yes. JetBrains added Nav 3 support in Compose Multiplatform 1.10.0 (January 2026) for all platforms: Android, iOS, desktop, and web.
6.2 Dependencies (KMP)
[versions]
multiplatform-nav3-ui = "1.0.0-alpha05"
[libraries]
jetbrains-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version.ref = "multiplatform-nav3-ui" }
Nav 3 ships as two artifacts:
navigation3-common— Core (transitive dependency)navigation3-ui— NavDisplay and UI components (separate CMP implementation)
Additional KMP libraries:
# Material 3 Adaptive
jetbrains-material3-adaptiveNavigation3 = { module = "org.jetbrains.compose.material3.adaptive:adaptive-navigation3", version.ref = "compose-multiplatform-adaptive" }
# ViewModel support
jetbrains-lifecycle-viewmodelNavigation3 = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "compose-multiplatform-lifecycle" }
6.3 Critical KMP Requirement: Polymorphic Serialization
On Android, Nav 3 uses reflection-based serialization for NavKey types. This does NOT work on non-JVM platforms (iOS, web). You must use polymorphic serialization.
rememberNavBackStack() has two overloads:
- Android-only:
rememberNavBackStack(startKey)— uses reflection - Multiplatform:
rememberNavBackStack(config, startKey)— requiresSavedStateConfiguration
For KMP, you MUST use the second overload:
@Serializable
data object Home : NavKey
@Serializable
data class Chat(val id: String) : NavKey
// Required for non-JVM platforms
private val config = SavedStateConfiguration {
serializersModule = SerializersModule {
polymorphic(NavKey::class) {
subclass(Home::class, Home.serializer())
subclass(Chat::class, Chat.serializer())
}
}
}
@Composable
fun App() {
val backStack = rememberNavBackStack(config, Home)
NavDisplay(backStack = backStack, ...)
}
6.4 Multi-Module KMP Pattern
For our multi-module setup, use sealed interfaces per feature module:
// feature/auth/api
@Serializable
sealed interface AuthRoute : NavKey
@Serializable data object Login : AuthRoute
@Serializable data object Register : AuthRoute
// feature/chat/api
@Serializable
sealed interface ChatRoute : NavKey
@Serializable data class Conversation(val id: String) : ChatRoute
// app module — aggregate all feature routes
private val config = SavedStateConfiguration {
serializersModule = SerializersModule {
polymorphic(NavKey::class) {
subclassesOfSealed<AuthRoute>()
subclassesOfSealed<ChatRoute>()
}
}
}
Alternatively, with Koin DI, each module can expose a SerializersModule and the app module combines them:
// Each feature module
val chatSerializerModule = SerializersModule {
polymorphic(NavKey::class) {
subclass(Conversation::class, Conversation.serializer())
}
}
// App module
val combinedConfig = SavedStateConfiguration {
serializersModule = chatSerializerModule + authSerializerModule + settingsSerializerModule
}
6.5 Impact on Our Current Setup
We currently use org.jetbrains.androidx.navigation:navigation-compose:2.9.2. For Nav 3:
| Current (Nav 2 KMP) | Nav 3 KMP |
|---|---|
org.jetbrains.androidx.navigation:navigation-compose:2.9.2 |
org.jetbrains.androidx.navigation3:navigation3-ui:1.0.0-alpha05 |
NavHost |
NavDisplay |
NavController |
SnapshotStateList + custom Navigator |
| Reflection-based routing | Must use SavedStateConfiguration with polymorphic serialization |
| Direct route access | Key-based entry access |
Key considerations:
- The JetBrains Nav 3 artifact is at 1.0.0-alpha05 (not yet stable for KMP)
- Android-side Nav 3 is stable at 1.0.1
- We must implement polymorphic serialization for all routes
- Our Koin-based DI can provide serializer modules per feature
- Browser history navigation (for web target) is expected in Nav 3 KMP 1.1.0
6.6 CMP Nav 3 Recipes
JetBrains maintains a Compose Multiplatform fork of the nav3-recipes:
7. Appendix: Version & Dependency Reference
AndroidX Dependencies (Android-only)
[versions]
nav3Core = "1.0.1" # Stable
# nav3Core = "1.1.0-rc01" # Latest RC
lifecycleViewmodelNav3 = "2.11.0-alpha03"
material3AdaptiveNav3 = "1.3.0-alpha09"
kotlinxSerializationCore = "1.9.0"
[libraries]
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }
androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" }
androidx-material3-adaptive-navigation3 = { module = "androidx.compose.material3.adaptive:adaptive-navigation3", version.ref = "material3AdaptiveNav3" }
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" }
Compose Multiplatform Dependencies (KMP)
[versions]
multiplatform-nav3-ui = "1.0.0-alpha05"
compose-multiplatform-adaptive = "1.3.0-alpha02"
compose-multiplatform-lifecycle = "2.10.0-alpha05"
[libraries]
jetbrains-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version.ref = "multiplatform-nav3-ui" }
jetbrains-material3-adaptiveNavigation3 = { module = "org.jetbrains.compose.material3.adaptive:adaptive-navigation3", version.ref = "compose-multiplatform-adaptive" }
jetbrains-lifecycle-viewmodelNavigation3 = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "compose-multiplatform-lifecycle" }
Nav 3 Recipes Repository
- Android: github.com/android/nav3-recipes (1.2k stars)
- CMP: github.com/terrakok/nav3-recipes
Available recipes:
- Basic, Saveable back stack, Entry provider DSL
- Deep links (basic + advanced)
- Dialog, BottomSheet, List-Detail, Two-pane, Supporting Pane
- Animations
- Navigation UI, Multiple back stacks
- Conditional navigation
- Modularized navigation (Hilt + Koin)
- ViewModel patterns (basic, Hilt, Koin, shared)
- Retain values for back stack composables
- Returning results (events + state)
- Fragment/View interop
Sources
- Navigation 3 Overview
- Navigation 3 Basics
- Navigation 3 Migration Guide
- Navigation 3 Save State
- Navigation 3 Metadata
- Navigation 3 Modularize
- Navigation 3 Scenes
- Navigation 3 Animations
- Navigation 3 Entry Decorators
- Navigation 3 Get Started
- Navigation 3 Release Notes
- Navigation 3 in Compose Multiplatform
- Compose Multiplatform 1.10.0 Blog Post
- Jetpack Navigation 3 is Stable (Blog)
- Announcing Jetpack Navigation 3 (Blog)
- nav3-recipes GitHub
- Deep Link Guide
- Shared ViewModel Recipe