---
title: "Charting a Course from Android Compose Nav2 to Nav3: Use Metadata for Transition Animations"
source: "/writing/charting-a-course-from-android-compose-nav2-to-nav3-use-metadata-for-transition-animations/"
---

Article

# Charting a Course from Android Compose Nav2 to Nav3: Use Metadata for Transition Animations

Lucas Kivi

July 27, 2026

A toucan holding a map. In the background is a boat steering wheel and a sextant.

_This is a part of a larger_ [_guide_](/writing/charting-a-course-from-android-compose-navigation-2-to-navigation-3) _for migrating from Android Compose Navigation 2 to Navigation 3. Checkout the parent guide for an overview of the migration._

Defining destination-level animations is a crucial part to any navigation framework. In Nav2 destination transitions were configured directly within the nav graph's builder.

composable<MainRoute.Inbox>(
    enterTransition = { slideInHorizontally() },
    exitTransition = { slideOutHorizontally() },
    popEnterTransition = { slideInHorizontally() },
    popExitTransition = { slideOutHorizontally() },
) {
    InboxScreen(...)
}

It was very easy to make helper functions to abstract away common animation patterns. Something like this:

inline fun <reified T : Any> NavGraphBuilder.horizontallySlidingComposable(
    noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit,
): Unit =
    composable<T>(
        content = content,
        enterTransition = { slideInHorizontally() },
        exitTransition = { slideOutHorizontally() },
        popEnterTransition = { slideInHorizontally() },
        popExitTransition = { slideOutHorizontally() },
    )

horizontallySlidingComposable<MainRoute.Inbox>) {
    InboxScreen(...)
}

This is a great strength and it is _still_ possible in Nav3!

### Improved Predictive Back Support

If you aren't familiar with this predictive back as a concept, take a peak at the official [docs](https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture) , but the basic idea is that the back animation is _predictive_ and therefore _scrubbable._

I start the gesture back navigation but never actually complete the back gesture and you can see that the fade and shrink transition is slowly played forward. In the end I cancel the back navigation and the transition is reversed such that the original screen is still completely visible.

In this predictive back demo I start the gesture back navigation but never actually release my finger which would allow the navigation to complete.

In Nav2 the predictive back behavior was the same as the pop animation, but like I said, _scrubbable_. In Nav3 we can actually specify a distinct predictive back behavior; more on that later.

### Nuts and Bolts

In Nav3, the animation behavior is still attached to the entry's definition, but the animation model shifts a little bit. Instead of attaching transitions directly to composable destinations, transitions are defined as metadata on entries using special keys:

-   `NavDisplay.TransitionKey`: for metadata to notify the `NavDisplay` of how the content should be animated when adding to the backstack.
-   `NavDisplay.PopTransitionKey`: for metadata to notify the `NavDisplay` of how the content should be animated when popping from backstack.
-   `NavDisplay.PredictivePopTransitionKey`: for metadata to notify the `NavDisplay` of how the content should be animated when popping from backstack using a predictive back gesture.

In practice, you will have something like this:

entry<MainRoute.Inbox>(
    metadata = metadata {
        put(NavDisplay.TransitionKey) {
            slideInHorizontally() togetherWith slideOutHorizontally()
        }
        put(NavDisplay.PopTransitionKey) {
            slideInHorizontally() togetherWith slideOutHorizontally()
        }
        put(NavDisplay.PredictivePopTransitionKey) {
            slideInHorizontally() togetherWith slideOutHorizontally()
        }
    },
) {
    InboxScreen(...)
}

The official `NavDisplay` API supports this metadata-based transition model, including defining those keys I mentioned for normal transitions, pop transitions, and predictive-pop transitions. And as I said, we can still make the helper functions:

inline fun <reified T : Any> EntryProviderScope<in T>.horizontallySlidingEntry(
    noinline content: @Composable (T) -> Unit,
): Unit =
    entry<T>(
        content = content,
        metadata = metadata {
            put(NavDisplay.TransitionKey) {
                TransitionDefaults.Enter.slideLeft togetherWith TransitionDefaults.Exit.stay
            }
            put(NavDisplay.PopTransitionKey) {
                TransitionDefaults.Enter.alreadyThere togetherWith TransitionDefaults.Exit.pushRight
            }
            put(NavDisplay.PredictivePopTransitionKey) {
                TransitionDefaults.Enter.alreadyThere togetherWith TransitionDefaults.Exit.pushRight
            }
        },
    )

horizontallySlidingEntry<MainRoute.Inbox>) {
    InboxScreen(...)
}

### To Recap

### In Nav2

The pattern looked like this:

-   Extend `NavGraphBuilder`
-   Register a `composable<T>()`
-   Attach transitions directly through destination transition parameters
-   Predictive back defaults to `popEnterTransition` and `popExitTransition` after 2.8.0

### In Nav3

The pattern becomes:

-   Extend `EntryProviderScope<K>`
-   Register an `entry<T>()`
-   Define separate `metadata` animation values for `NavDisplay.TransitionKey`, `NavDisplay.PopTransitionKey`, and `NavDisplay.PredictivePopTransitionKey`

### Conclusion

The shape of the basic animation API is very similar once you get used to the new metadata mapping system. Additionally, you must specify an animation with the key of `NavDisplay.PredictivePopTransitionKey` if you want to override the default predictive back behavior.

### Migration guidance

Consider these rules of thumb when migrating animation behavior from Nav2 to Nav3:

-   If a destination had custom transitions in Nav2, move that behavior into `entry` metadata in Nav3.
-   Start specifying predictive back animations.
-   For destinations with reusable animation patterns, it still makes sense to keep helper abstractions.

**Up next**: [rework bottom sheet navigation destinations](/writing/charting-a-course-from-android-compose-nav2-to-nav3-rework-bottom-sheet-navigation-destinations) .

_Lucas is very animated (often predictably so) at Livefront._

-   Lucas Kivi

    Software Engineer

    [More from Lucas](/team/lucas-kivi/)

    Lucas Kivi

### Tags

[Mobile Apps](/insights/all/?topic=mobile-apps)

### Share

-   Copied

## View these next.

[See all](/insights/all/?type=writing)

-   [

    Article

    How To Sabotage Your Project Using Inconsistency

    Collin Flynn

    ](/writing/how-to-sabotage-your-project-using-inconsistency/)
-   [

    Article

    Unit Testing race conditions by creating chaos (Swift)

    Sean Berry

    ](/writing/unit-testing-race-conditions-by-creating-chaos-swift/)
-   [

    Article

    UIApplicationDelegate call sequence reference

    Sean Berry

    ](/writing/uiapplicationdelegate-call-sequence-reference/)
