Library / SDK
adrielcafe/voyager avatar
adrielcafe/voyager

Voyager: a Compose Multiplatform navigation library from adrielcafe

🛸 A pragmatic navigation library for Compose Multiplatform

3,089 stars166 forksKotlinMIT

At a glance

What is it?
Voyager is a navigation library for Jetpack Compose and Compose Multiplatform that replaces NavHost with a Navigator composable and a Screen interface. It targets Android, iOS, Desktop and Web, but its release history is uneven.
Who is it for?
Voyager is for Compose Multiplatform teams that want navigation expressed as ordinary composables and a Screen interface rather than a NavHost graph, and who are comfortable reading the project website because the README itself is thin. It is not for teams that need a fast release cadence or a large third-party ecosystem of extensions.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 117 days ago.
What is it written in?
Mainly Kotlin, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Voyager replaces, and for whom

The problem Voyager addresses is the gap between Jetpack Compose's declarative UI model and navigation. Compose renders from state, but a navigation graph is usually declared separately, with string routes and a host composable that owns the back stack. Voyager removes that separation. A destination is a class implementing Screen, and its UI lives in a Content composable. The README describes the result as scalable Single-Activity apps powered by a pragmatic API, and the sample at the top of the README is a single ComponentActivity whose setContent block calls Navigator(HomeScreen()).

The intended audience is Kotlin developers building Compose Multiplatform applications. The README lists Android, iOS, Desktop and Web as supported platforms, and the repository contains a samples/multiplatform directory alongside samples/android and samples/multiplatform-iosApp. A team that only ships Android and is happy with the official Navigation component has less reason to look here. A team sharing UI code across mobile and desktop has more.

The Screen, ScreenModel and Navigator mechanism

Voyager's data flow runs through three types. Screen is an interface with a Content composable and, by convention, an associated ScreenModel, which the README calls a ViewModel equivalent. rememberScreenModel<HomeScreenModel>() inside Content obtains that model, scoped to the screen rather than to the activity. Navigator is the composable that hosts a stack of screens and renders the top one.

The repository layout shows how the concerns are split into separate Gradle modules: voyager-core, voyager-navigator, voyager-screenmodel, voyager-tab-navigator, voyager-bottom-sheet-navigator, voyager-transitions, voyager-lifecycle-kmp, plus integration modules voyager-koin, voyager-kodein, voyager-hilt, voyager-rxjava and voyager-livedata. That module list is the clearest statement of the library's scope: tab navigation and bottom sheet navigation are first-class navigator types, not patterns you assemble yourself, and the DI integrations exist because ScreenModel is the library's own lifecycle owner rather than an Android ViewModel. The README also lists an Android ViewModel integration with Hilt support for teams that want to keep the platform class.

Because destinations are classes, multi-module navigation is type-safe in the sense the README claims: a module can expose a Screen subclass and another module can push it without a shared string constant. The trade-off is that every destination is a type the compiler must see, which is a different coupling story from a route table.

Installing Voyager and pushing a second screen

The README does not contain a dependency snippet. It points to the project website at voyager.adriel.cafe for documentation and APIs, and the badges link to Maven Central under the group cafe.adriel.voyager. The repository splits functionality across modules, so a Gradle build declares the navigator module plus whichever other module the app uses. The exact version string is the one published on Maven Central; the README does not pin one, so the version below is a placeholder you replace with the published one.

The README's own example defines a screen and hosts it. Navigator is called once, from setContent, and the screen it receives becomes the root of the stack:

kotlin
class HomeScreen : Screen {

    @Composable
    override fun Content() {
        val screenModel = rememberScreenModel<HomeScreenModel>()
        // ...
    }
}
kotlin
class SingleActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Navigator(HomeScreen())
        }
    }
}

After that compiles and runs, the reader should see HomeScreen rendered as the only entry in the stack. Pushing a second screen is done from inside a Content composable by obtaining the navigator and calling push with a new Screen instance. The README does not print that call, so check the basicNavigation sample under samples/android before writing it from memory.

Where Voyager is the wrong choice

The release history is the first thing to weigh. The most recent release listed is 2.2.21-1.10.3 on 2026-06-06, built against Kotlin 2.2.21 and Compose Multiplatform 1.10.3. Before it, 2.0.0-alpha01 landed on 2025-08-17 and 1.0.1 on 2024-12-19. That is roughly two releases in the better part of two years, with an alpha sitting between them. The last push to the main branch was on 2026-06-06, so the repository is not archived and work has happened recently, but a library tied to Compose Multiplatform has to track that platform's compiler and runtime releases. A team that upgrades Compose Multiplatform on the day a new version ships may find itself waiting.

The second constraint is documentation surface. The README is essentially a feature list with links. Deep linking, state restoration, back press handling and lifecycle callbacks are each one line pointing at a page on voyager.adriel.cafe. The README does not document rollback, migration between major versions, or what changed between 1.0.1 and 2.x. If your team needs a written upgrade path inside the repository, this is not it.

The third is the ScreenModel design itself. It is deliberately not an Android ViewModel, which is what makes it work on iOS, Desktop and Web, and what makes the Koin, Kodein, Hilt, RxJava and LiveData modules necessary. If your codebase is already built around androidx.lifecycle.ViewModel and Hilt, you are adopting a parallel lifecycle concept alongside the one you have.

Voyager against Compose Multiplatform's own navigation

The obvious alternative is the navigation library maintained as part of the Compose Multiplatform effort, which models destinations as a graph of routes and hands rendering to a NavHost composable. The difference in approach is structural. In the graph model, routes are data, often serializable types or strings, and the host resolves them; the back stack is a value the host owns and you observe. In Voyager, destinations are Screen instances you construct and push, and the navigator is a composable in your tree. Voyager's model reads more naturally if you think of screens as objects; the graph model reads more naturally if you think of navigation as configuration, and it tends to be the safer bet when you want the platform vendor's release cadence behind you.

Voyager does have features the README lists that are not trivially reproduced: BottomSheet navigation and Tab navigation are separate navigator modules, nested navigation with multiple stacks and parent navigation is called out explicitly, and the tab navigation is compared in the README to the YouTube app. If those patterns match your app's shape, the module split means you pull in only what you use.

Licence and the cost of keeping up

Voyager is MIT licensed, per the repository's LICENSE.md and the licence badge in the README. MIT permits commercial and closed-source use and requires preserving the copyright notice and licence text. This is not legal advice; confirm the terms against the LICENSE.md file in the repository before relying on them.

The upgrade cost is the more practical question. Because the library tracks Kotlin and Compose Multiplatform versions, the version string itself carries the pairing: 2.2.21-1.10.3 encodes Kotlin 2.2.21 and CMP 1.10.3. That convention makes it easy to see which Compose Multiplatform release a Voyager artifact was built against, and it also means you cannot pick up a Voyager release for a Compose Multiplatform version the maintainer has not built against. Budget for that lag rather than assuming you can move both dependencies in the same commit.

Editorial conclusion

Voyager is for Compose Multiplatform teams that want navigation expressed as ordinary composables and a Screen interface rather than a NavHost graph, and who are comfortable reading the project website because the README itself is thin. It is not for teams that need a fast release cadence or a large third-party ecosystem of extensions. Before adopting, check whether the artifacts on Maven Central match the Kotlin and Compose Multiplatform versions in your build, and read the state restoration and deep linking pages, since the README only links to them.

Frequently asked questions

How do you install Voyager in a Compose Multiplatform project?

The README does not include a dependency snippet; it points to voyager.adriel.cafe for documentation and the badges link to Maven Central under the group cafe.adriel.voyager. Add the navigator artifact for the version published on Maven Central, plus the module for each navigator type you use.

How do you use Voyager for navigation in Compose?

Define a class implementing Screen with a Content composable, then host it by calling Navigator(HomeScreen()) inside setContent, as the README example shows. Screen-scoped state comes from rememberScreenModel inside Content.

Which platforms does Voyager support?

The README lists Android, iOS, Desktop and Web under supported platforms, and the repository contains multiplatform and multiplatform-iosApp sample directories in addition to the Android samples.

Does Voyager work with Hilt or Koin?

Yes. The repository contains separate voyager-hilt, voyager-koin and voyager-kodein modules, and the README lists ScreenModel integrations for Koin, Kodein, Hilt, Coroutines, RxJava and LiveData, plus an Android ViewModel integration with Hilt support.

What is the latest Voyager release and which Kotlin version does it use?

The most recent release listed is 2.2.21-1.10.3, published on 2026-06-06, and the release title states it targets Kotlin 2.2.21 and Compose Multiplatform 1.10.3. The version string encodes that pairing.

Official sources

  1. adrielcafe/voyager on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/adrielcafe-voyager.svg)](https://hysenlabs.com/projects/adrielcafe-voyager)