---
title: Dynamic Navigation in Android
description: Learn how to enable dynamic rendering of new stories by setting up catch-all navigation in Android.
url: https://www.storyblok.com/docs/guides/android/dynamic-routing
---

# Dynamic Navigation in Android

Use [Navigation 3](https://developer.android.com/guide/navigation/navigation-3) to set up a catch-all navigation strategy in your Android project and render new stories dynamically.

## Add dependencies

In the version catalog TOML file, add the Navigation 3 libraries.

gradle/libs.versions.toml

```kotlin
[versions]
agp = "9.2.1"
…
storyblok = "0.3.0"
nav3Core = "1.0.1"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
…
storyblok-material3-android = { group = "com.storyblok", name = "storyblok-material3-android", version.ref = "storyblok" }
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
…
```

Update `app/build.gradle.kts` to add the dependencies.

app/build.gradle.kts

```kotlin
…
dependencies {
  implementation(platform(libs.androidx.compose.bom))
  …
  implementation(libs.storyblok.material3.android)
  implementation(libs.androidx.navigation3.ui)
  implementation(libs.androidx.navigation3.runtime)
}
```

Now select **Sync Project with Gradle Files** to download the added dependencies and re-analyze the project.

## Create a story navigation key

Create a `StoryKey.kt` file to define a navigation key that can represent any story, identified by either its UUID or slug.

app/src/main/java/com/example/myapplication/StoryKey.kt

```kotlin
package com.example.myapplication

import androidx.navigation3.runtime.NavKey
import com.storyblok.cdn.schema.Component
import com.storyblok.cdn.schema.Story
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlin.uuid.Uuid

@Serializable
data class StoryKey(
  @Transient
  val story: Story<out Component>? = null,
  @EncodeDefault
  val uuid: Uuid? = story?.uuid,
  @EncodeDefault
  val slug: String? = story?.slug,
) : NavKey

val HomeKey = StoryKey(slug = "home")
```

`StoryKey` is a `NavKey` that persists the `uuid` or `slug` of a story to the back stack. It can also be constructed with a [`Story`](https://storyblok.github.io/storyblok-kotlin/content-api-client/com.storyblok.cdn.schema/-story/index.html) instance for immediate display when navigating between screens.

## Display the back stack

In your `MainActivity.kt` file, add the code to initialize and use a [`NavDisplay`](https://developer.android.com/reference/kotlin/androidx/navigation3/ui/NavDisplay.composable) to render the top of the back stack.

app/src/main/java/com/example/myapplication/MainActivity.kt

```kotlin
…
import kotlinx.coroutines.flow.onCompletion
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay
import androidx.navigation3.runtime.entryProvider

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge()
    setContent {
      MyApplicationTheme {
        Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->

          val backStack = rememberNavBackStack(HomeKey)

          Storyblok(
            accessToken = "YOUR_ACCESS_TOKEN",
            version = if (BuildConfig.DEBUG) Draft else Published,
            region = EU, // Choose the correct region from your Space.
            …
          ) {
            NavDisplay(
              backStack,
              Modifier.padding(innerPadding),
              entryProvider = entryProvider {
                entry<StoryKey> { key ->

                  var isRefreshing: Boolean by remember { mutableStateOf(true) }

                  val story by
                    remember {
                      snapshotFlow { isRefreshing }
                        .filter { it }
                        .flatMapLatest {
                          story("home").onCompletion { isRefreshing = false }
                          val story = when(key.uuid) {
                            null -> story(slug = key.slug!!)
                            else -> story(uuid = key.uuid)
                          }
                          story.onCompletion { isRefreshing = false }
                        }
                    }
                    .collectAsStateWithLifecycle(null)
                    .collectAsStateWithLifecycle(key.story)

                  PullToRefreshBox(
                    isRefreshing = isRefreshing,
                    onRefresh = { isRefreshing = true },
                    modifier = Modifier.fillMaxSize()
                  ) {
                    story?.content?.let { Block(it, Modifier.padding(innerPadding)) }
                    story?.content?.let { Block(it) }
                  }
                }
              }
            )
          }
        }
      }
    }
  }
}
…
```

The single `entry<StoryKey>` handles every possible story destination. It fetches the story by UUID or slug, populating the initial value of [`collectAsStateWithLifecycle`](https://developer.android.com/reference/kotlin/androidx/lifecycle/compose/collectAsStateWithLifecycle.composable) with the key’s story instance so available content appears immediately.

> [!TIP]
> To navigate to a story from a block composable, push a `StoryKey` onto the back stack.
> 
> ```kotlin
> backStack.add(StoryKey(story = article)) // from Story instance
> backStack.add(StoryKey(slug = "articles/my-article")) // by slug
> ```

With this approach, the project automatically handles new stories that are added to the space and pushed onto the back stack.

## Related resources

[Content Delivery API: Retrieve a Single Story](/docs/api/content-delivery/v2/stories/retrieve-a-single-story)

[Android Developers: Navigation 3 Overview](https://developer.android.com/guide/navigation/navigation-3)

[Android Developers: Displaying the Back Stack in Navigation 3](https://developer.android.com/guide/navigation/navigation-3/basics#display-back)

## Pagination

-   [Previous: Visual Preview in Android](/docs/guides/android/visual-preview)
-   [Next: Content Modeling in Android](/docs/guides/android/content-modeling)
