{"id":20490170,"url":"https://github.com/open-turo/nibel","last_synced_at":"2026-04-15T23:03:39.043Z","repository":{"id":181898505,"uuid":"667584375","full_name":"open-turo/nibel","owner":"open-turo","description":"Type-safe navigation library for seamless adoption of Jetpack Compose in fragment-based Android apps.","archived":false,"fork":false,"pushed_at":"2026-04-14T00:49:03.000Z","size":1543,"stargazers_count":83,"open_issues_count":15,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-14T02:25:47.517Z","etag":null,"topics":["android","jetpack-compose","kotlin","navigation"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/open-turo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-07-17T21:05:20.000Z","updated_at":"2026-04-13T11:50:08.000Z","dependencies_parsed_at":"2023-12-13T01:55:38.921Z","dependency_job_id":"bf500449-d707-4f1c-976a-8b74c54583b2","html_url":"https://github.com/open-turo/nibel","commit_stats":null,"previous_names":["open-turo/nibel"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/open-turo/nibel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-turo%2Fnibel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-turo%2Fnibel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-turo%2Fnibel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-turo%2Fnibel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/open-turo","download_url":"https://codeload.github.com/open-turo/nibel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-turo%2Fnibel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31861802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"ssl_error","status_checked_at":"2026-04-15T15:24:39.138Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","jetpack-compose","kotlin","navigation"],"created_at":"2024-11-15T17:15:50.962Z","updated_at":"2026-04-15T23:03:39.025Z","avatar_url":"https://github.com/open-turo.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Nibel 💫\n\nNibel — is a type-safe navigation library for seamless integration of Jetpack Compose in fragment-based Android apps.\n\nWhen we built it at Turo, our goal was to ensure a proper Jetpack Compose experience for the team when creating new features while keeping them compatible with the rest of the codebase automatically.\n\nBy leveraging the power of annotation processing, Nibel provides a unified and type-safe way of navigating between screens in the following navigation scenarios:\n\n- **fragment → compose**\n- **compose → compose**\n- **compose → fragment**\n\nNibel supports both **single-module** and **multi-module** navigation out-of-the-box. The latter is especially useful when navigating between feature modules that do not depend on each other directly.\n\n- [Installation](#installation)\n- [Basic usage](#basic-usage)\n- [Multi-module navigation](#multi-module-navigation)\n- [Sample app](#sample-app)\n\n## Materials\n\n- [Designing Jetpack Compose architecture for a gradual transition from fragments on Android](https://medium.com/turo-engineering/designing-jetpack-compose-architecture-for-a-gradual-transition-from-fragments-on-android-b11ee5f19ba8) - blog post at Turo Engineering.\n- [Introducing Nibel - a navigation library for seamless adoption of Jetpack Compose in fragment-based Android apps](https://medium.com/@morfly/introducing-nibel-a-navigation-library-for-adopting-jetpack-compose-in-fragment-based-apps-541c7b2f3f84) - blog post at Turo Engineering.\n- [Migrating Android apps from Fragments to Jetpack Compose at Turo](https://youtu.be/SO0qjys_d08?si=xLtdbyp5ZRXXAp9j) - talk at Android Worldwide.\n- [Migrating Android apps from Fragments to Jetpack Compose with Nibel](https://www.droidcon.com/2023/10/06/migrating-android-apps-from-fragments-to-jetpack-compose-with-nibel/) - talk at droidcon New York 2023.\n\n## Installation\n\nNibel consists of 2 components: **runtime** and **compiler**. The latter enables code generation to provide a type-safe way of navigating between screens.\n\nIn the `build.gradle.kts` of your feature module add the dependencies below.\n\n```kotlin\ndependencies {\n  implementation(\"com.openturo.nibel:nibel-runtime:x.y.z\")\n  ksp(\"com.openturo.nibel:nibel-compiler:x.y.z\")\n}\n```\n\nDon't forget to apply a KSP plugin and enable Jetpack Compose for every module where Nibel is used.\n\n```kotlin\nplugins {\n  id(\"com.google.devtools.ksp\")\n}\n```\n\nThe latest version of Nibel is [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.openturo.nibel/nibel-runtime/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.openturo.nibel/nibel-runtime).\n\n## Basic usage\n\n### Configuration\n\nTo start using Nibel, just call the `Nibel.configure()` function to initialize it in the `Application.OnCreate`.\n\n### Delaring a screen\n\nWhen working with Nibel, all you need to do is to annotate a composable function that represents a screen with a `@UiEntry` annotation.\n\n```kotlin\n@UiEntry(\n  type = ImplementationType.Fragment // one of \u003cFragment|Composable\u003e\n)\n@Composable\nfun FirstScreen() { ... }\n```\n\nWhen you build the code, there will be generated a `{ComposableName}Entry` class that serves as an entry point to the screen.\n\nThe type of the generated entry differs depending on the `ImplementationType` specified in the annotation. Each type serves a specific scenario and can be one of:\n\n- `Fragment` - generates a fragment that uses the annotated composable as its content. It makes the compose screen look like a fragment to other fragments and is crucial in **fragment → compose** navigation scenarios.\n- `Composable` - generates a small wrapper class over a composable. It is normally used in **compose → compose** and **compose → fragment** navigation scenarios.\n\n\u003e Use `ImplementationType.Composable` as much as you can to reduce the performance overhead by avoiding instantiation of fragment-related classes for each screen under-the-hood.\n\n### Navigating fragment to compose\n\nTo navigate from an existing fragment to a `FirstScreen` composable you should treat a generated `FirstScreenEntry` as a fragment and use a transaction for navigation.\n\n```kotlin\nclass ZeroScreenFragment : Fragment() {\n  ...\n  requireActivity().supportFragmentManager.commit {\n    replace(android.R.id.content, FirstScreenEntry.newInstance().fragment)\n  }\n}\n```\n\n### Declaring a screen with args\n\nFor screens with arguments, just pass the class of your `Parcelable` args in the `@UiEntry` annotation.\n\n```kotlin\n@UiEntry(\n  type = ImplementationType.Composable,\n  args = SecondScreenArgs::class // optional Parcelable args\n)\n@Composable\nfun SecondScreen(\n  args: SecondScreenArgs, // optional param\n) { ... }\n```\n\nOptionally, arguments could be declared in params of the composable function, so that the instance is automatically provided by Nibel.\n\n\u003e **Warning**: If argument types in the annotation and function params do not match, a compile time error will be thrown.\n\n### Navigating compose to compose\n\nThe core navigation component within compose screens is `NavigationController`. It can be optionally declared in params of the composable function, so that the instance is automatically provided by Nibel.\n\nTo navigate from `FirstScreen` to `SecondScreen`, use `navigateTo` with an instance of a generated entry class.\n\n```kotlin\n@UiEntry(type = ImplementationType.Fragment)\n@Composable\nfun FirstScreen(\n  navigator: NavigationController // optional param\n) {\n  ...\n  val args = SecondScreenArgs(...)\n  navigator.navigateTo(SecondScreenEntry.newInstance(args))\n}\n```\n\n\u003e You can navigate between screens of any `ImplementationType` with no limitations but it is recommended to use `Composable` for every screen unless it is reached from an existing fragment.\n\n### Navigating compose to fragment\n\nWhen adopting Jetpack Compose there if often the need to navigate from compose screens to old fragments.\n\n```kotlin\nclass ThirdScreenFragment : Fragment() { ... }\n```\n\nTo navigate from `SecondScreen` composable to `ThirdScreenFragment` just wrap the latter with `FragmentEntry`.\n\n```kotlin\nval fragment = ThirdScreenFragment()\nnavigator.navigateTo(FragmentEntry(fragment))\n```\n\n## Multi-module navigation\n\nIn multi-module apps it is common to have feature modules that do not depend on each other directly. This leads to inability of obtaining direct references to generated entry classes.\n\nNibel provides an easy way of multi-module navigation in a type-safe manner using a concept of destinations. Destination — is a simple data type that stands for a navigation intent. It is located in a separate module available to other feature modules.\n\n```\n featureA          featureB\n  module            module\n    │                  │\n    └──► navigation ◄──┘\n           module\n```\n\n### Declaring a destination\n\nThe most basic destination is an `object` that implements `DestinationWithNoArgs` an is declared in a separate navigation module, available to other feature modules.\n\n```kotlin\n// navigation module available to other feature modules\nobject FirstScreenDestination : DestinationWithNoArgs\n```\n\nA destination then must be associated with a corresponding compose screen. This time there should be used `UiExternalEntry` annotation instead of `UiEntry`.\n\n```kotlin\n// feature module\n@UiExternalEntry(\n  type = ImplementationType.Fragment,\n  destination = FirstScreenDestination::class\n)\n@Composable\nfun FirstScreen() { ... }\n```\n\nA destination must be associated with **exactly one** compose screen. Otherwise, a compile time error will be thrown.\n\n\u003e `UiExternalEntry` includes all the functionallity of `UiEntry`. This includes generating entry classes for navigating within a single feature module.\n\n### Navigating fragment to compose\n\nTo navigate from an existing fragment to a `FirstScreen` composable, use a destination to obtain a `FirstScreenEntry` instance by calling `Nibel.newFragmentEntry`. Treat it as a fragment and use a transaction for navigation.\n\n```kotlin\nclass ZeroScreenFragment : Fragment() {\n  ...\n  requireActivity().supportFragmentManager.commit {\n    val entry = Nibel.newFragmentEntry(FirstScreenDestination)!!\n    replace(android.R.id.content, entry.fragment)\n  }\n}\n```\n\n### Defining a destination with args\n\nFor a screen with arguments, make sure its associated destination is a `data class` that implements `DestinationWithArgs` where the args should be `Parcelable`.\n\n```kotlin\ndata class SecondScreenDestination(\n  override val args: SecondScreenArgs // Parcelable args\n) : DestinationWithArgs\u003cSecondScreenArgs\u003e\n```\n\nNow, all that's left to do is to connect the destination type with a `@UiExternalEntry`, so that the arguments are automatically available as params of a composable function.\n\n```kotlin\n@UiExternalEntry(\n  type = ImplementationType.Composable,\n  destination = SecondScreenDestination::class\n)\n@Composable\nfun SecondScreen(args: SecondScreenArgs) { ... }\n```\n\n### Navigating compose to compose\n\nTo navigate from `FirstScreen` to `SecondScreen` both of which are composables defined above, use `navigateTo` with an instance of a destination assiciated with the target screen.\n\n```kotlin\nval args = SecondScreenArgs(...)\nnavigator.navigateTo(SecondScreenDestination(args))\n```\n\n### Navigating compose to fragment\n\nTo navigate from `SecondScreen` composable to `ThirdScreenFragment` annotate the latter with `@LegacyExternalEntry` and associate it with a destination.\n\n```kotlin\n@LegacyExternalEntry(destination = ThirdScreenDestination::class)\nclass ThirdScreenFragment : Fragment() {\n  ...\n  // Accessing screen arguments\n  arguments?.getNibelArgs\u003cThirdScreenArgs\u003e()\n}\n```\n\nThen, use the destination for navigation.\n\n```kotlin\nval args = ThirdScreenArgs(...)\nnavigator.navigateTo(ThirdScreenDestination(args))\n```\n\n## Sample app\n\nCheck out a [sample app](sample) for demonstration of various scenarios of using Nibel in practice.\n\n## Contributing\n\nPull requests are welcome! See [here](https://github.com/open-turo/contributions) for guidelines on how to contribute to this project.\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2023 Turo Open Source\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-turo%2Fnibel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopen-turo%2Fnibel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-turo%2Fnibel/lists"}