Nav 9 min read

Jetpack Navigation 2.10 Beta: KMP on 9 Platforms, Richer Predictive Back, and the Maintenance Mode Signal

Navigation 2.10.0-beta01 dropped on July 29, and it carries a few things worth paying attention to regardless of whether you're still building with the classic Navigation library or have already migrated to Navigation3. The headline is multiplatform support — navigation-common, navigation-runtime, and navigation-testing now compile for Desktop, Linux, macOS, iOS, JavaScript, WASM, tvOS, and watchOS alongside Android. That's significant for KMP projects that share business logic and want navigation primitives to travel with it.

But the more interesting signal is what this release says about the library's trajectory. Navigation 2.x is heading toward maintenance mode — the same place the Views toolkit landed last week. You're not going to get new features here; you're going to get stability, KMP breadth, and critical bug fixes. If you're starting a new screen from scratch, the answer is increasingly obvious. If you're maintaining an existing app with hundreds of navigation destinations, this release is actually good news: a stable, battle-hardened library with a clear support horizon.

9
Platforms supported (Android, Desktop, Linux, macOS, iOS, JS, WASM, tvOS, watchOS)
API 23
New minimum SDK (raised from API 21)
Beta
Approaching stable — no planned feature additions after 2.10

The KMP Story: What Actually Changes

KMP support in Navigation 2.10 isn't cosmetic. Three core modules now publish artifacts for every major non-Android target: navigation-common, navigation-runtime, and navigation-testing. If you maintain a shared module in a KMP project — say, a viewmodel layer that drives screen transitions — you can now depend on navigation-common from that module directly rather than putting Android-specific navigation logic behind an expect/actual boundary.

Two new common APIs make this concrete. First, NavController.handleDeepLink(request: NavDeepLinkRequest) replaces the Android-only overload that took a platform Intent. This function now lives in the common source set, so deep link handling logic is portable across targets without any platform bridging. Second, NavUri is a new platform-agnostic URI type that replaces android.net.Uri in navigation APIs — the Android-specific class that made it impossible to share deep link construction code between Android and non-Android targets.

// Before 2.10 (Android only)
val request = NavDeepLinkRequest.Builder
    .fromUri(Uri.parse("myapp://product/42"))
    .build()
navController.handleDeepLink(intent)

// With 2.10 (common, works on all KMP targets)
val uri = NavUri("myapp://product/42")
val request = NavDeepLinkRequest.Builder
    .fromUri(uri)
    .build()
navController.handleDeepLink(request)

For a pure Android app this doesn't change anything today — you can still use android.net.Uri on Android and Navigation will accept it. But if you're on a KMP project sharing a module between Android and iOS, or building a Compose Multiplatform app targeting Desktop, this is the piece that was missing before.

Worth knowing: the fragment-based navigator artifacts (navigation-fragment, navigation-ui) are Android-only and aren't getting KMP targets. KMP support is in the common runtime layer only. If your navigation graph is Fragment-based, this update doesn't give you multiplatform reach — it's aimed at Compose Multiplatform and shared viewmodel patterns.

NavBackStackEntryInfo — Predictive Back Gets Smarter

The other notable addition in beta01 is NavBackStackEntryInfo, a new class that exposes back stack snapshots during navigation events. Before this, if you wanted to implement a custom predictive back animation in a NavHost-based app, you were working with limited context about what was actually on the back stack at the moment the gesture fired. The animation had to be generic because the gesture handler couldn't see the full picture.

NavBackStackEntryInfo changes that. The lambda params for predictivePopEnterTransition and predictivePopExitTransition now receive entry info, so you can branch your animation based on what destination is being revealed:

NavHost(
    navController = navController,
    startDestination = Home,
    predictivePopEnterTransition = { backStackEntryInfo ->
        // Slide from left for standard destinations,
        // scale-in for modal-style screens
        when (backStackEntryInfo.destination.route) {
            "modal_detail" -> scaleIn(initialScale = 0.92f) + fadeIn()
            else -> slideInHorizontally { -it / 3 } + fadeIn()
        }
    },
    predictivePopExitTransition = { backStackEntryInfo ->
        when (backStackEntryInfo.destination.route) {
            "modal_detail" -> scaleOut(targetScale = 1.08f) + fadeOut()
            else -> slideOutHorizontally { it / 3 } + fadeOut()
        }
    }
) {
    composable { HomeScreen() }
    composable { ProductDetailScreen() }
    composable("modal_detail") { ModalDetailScreen() }
}

This is particularly useful if you've mixed navigation patterns — some destinations that behave like full-screen replacements and others that feel more like sheets or dialogs but live in the back stack. The gesture can now drive visually distinct transitions per destination pair instead of a one-size-fits-all animation. I've been doing a version of this manually by wrapping NavHost with custom back gesture handling, and it's genuinely messy. Having it as a first-class API is cleaner.

What predictive pop transitions actually mean for users

Android's predictive back gesture gives users a live preview of where swiping back will take them before they commit to the gesture. If your predictivePopEnterTransition is set, that preview is driven by your animation instead of the system default, and it scrubs in real-time as the user drags. The richer the NavBackStackEntryInfo you can read, the more contextually accurate that preview is — users see the right animation for the specific destination they're returning to, not a generic one.

In Nodat, where we navigate between a main feed, post detail, and a profile overlay, these three destinations genuinely deserve different back animations. Before this API I had to accept either a single global transition or a lot of boilerplate state-tracking outside NavHost. This is cleaner either way.

Min SDK Bump: API 21 → API 23

Navigation 2.10 raises the minimum supported SDK from API 21 (Android 5.0) to API 23 (Android 6.0), aligning with the broader AndroidX library consolidation that happened across most Jetpack libraries earlier this year.

In practice, this almost certainly doesn't affect you. API 23 has had north of 99% device coverage in the Play Console for several years. The only scenario where this is a blocker is if you're maintaining an app with a hard requirement to run on Android 5.x — niche industrial or enterprise hardware, some regional markets with very old device stacks. If you're in that situation, staying on Navigation 2.9.x (current stable is 2.9.8) is the right call; Google will continue publishing critical bug fixes to the 2.9 line.

The Deep Link Security Fix Worth Knowing About

Alpha06 (July 1) also landed a security-adjacent fix that beta01 carries forward: handleDeepLink now validates that the incoming deep link matches a known destination before processing it. Previously, a malformed or unexpected deep link could be partially processed even if no destination matched it. The fix ensures only recognized deep links — ones that match a registered deep link pattern in your nav graph — are handled at all. Unrecognized deep links are now dropped silently.

If you handle deep links from external sources (push notifications, web redirects, app-to-app links), this tightens the behavior in your favor. Attackers probing your deep link surface no longer get even partial handling on unknown paths. No action needed from you — just awareness that the behavior changed.

Where Navigation 2.x Is Headed: The Maintenance Mode Signal

Here's the honest take. Navigation 2.10 is probably the last feature release for this library track. The documentation already describes Navigation 2.x as being in maintenance mode, meaning only critical bug fixes from here. No new navigation patterns, no new transition APIs, no new deep link features beyond what's already there.

This mirrors what happened with Views last week. It's not an emergency — both libraries will remain fully supported for years — but the message is clear: Google has made its architectural bet on Navigation3 and Compose, and new investment is going there.

For an app like Samachar, which I built entirely on the classic Navigation library with a Fragment-based UI, this means I have a choice to make over the next year or two: migrate incrementally to Compose + Navigation3, or accept that the navigation layer is "done" and treat it like a stable dependency I don't have to think about much. Both are legitimate choices. Navigation 2.10 is stable, well-understood, and will keep working. The cost is you're not getting new capabilities, and the tooling investment is going elsewhere.

Navigation 2.10 vs. Navigation3: the practical decision tree

Upgrading to 2.10.0-beta01

The API surface from 2.9.x is largely stable. The two changes that require code edits are the NavUri type (if you're explicitly passing android.net.Uri into navigation APIs in shared code) and the min SDK bump (if you're on API 21).

// build.gradle.kts
dependencies {
    val navVersion = "2.10.0-beta01"

    // Compose-based navigation
    implementation("androidx.navigation:navigation-compose:$navVersion")

    // Fragment-based navigation
    implementation("androidx.navigation:navigation-fragment:$navVersion")
    implementation("androidx.navigation:navigation-ui:$navVersion")

    // Testing
    androidTestImplementation("androidx.navigation:navigation-testing:$navVersion")
}

// Serialization plugin needed for type-safe routes
plugins {
    kotlin("plugin.serialization") version "2.0.21"
}

Beta status means API stability is locked — the team isn't planning breaking changes before the stable release. Running it in production is low-risk for most apps. That said, this is still technically pre-stable, so if you're in a context where any pre-stable dependency is a policy violation (some enterprise environments), wait for the stable release, which should follow relatively quickly given beta01 is the first beta.

The bottom line: Navigation 2.10.0-beta01 is a good release that honest about its scope. KMP support lands where it matters (common runtime, not Android-specific navigators), predictive back gets a proper API, and the security posture tightens. It's not a reason to defer a Navigation3 migration if you were already planning one — but it's not a reason to panic if you weren't. Your existing Navigation 2.x graphs will work, and work well, for a long time to come.

Comments 0

No comments yet. Be the first to leave one!

Leave a comment