Designing Jetpack Compose Architecture for a Gradual Transition from Fragments on Android
Article Summary
Turo's Android team faced a challenge: how to adopt Jetpack Compose without rewriting their entire fragment-based app overnight.
Staff Engineer Pavlo Stavytskyi shares how Turo designed an architecture that lets developers write pure Compose code while maintaining seamless compatibility with legacy fragments. The solution uses code generation and abstraction layers to hide complexity.
Key Takeaways
- Single @UiEntry annotation generates fragment wrappers automatically for compatibility
- navigateTo() function abstracts all four navigation scenarios under one API
- Destinations concept eliminates reflection based navigation boilerplate code
- KSP generates factories injected via Dagger for type safe routing
- Dynamic NavHost destinations survive configuration changes with rememberSaveable
Turo built a migration path where engineers write pure Compose code while code generation handles all fragment compatibility automatically.
About This Article
Turo's codebase had a type safety problem in navigation. The navigation module couldn't depend on feature modules, so developers had to use reflection and fully qualified class names to create screens.
Pavlo Stavytskyi's team built a Destinations concept using @UiExternalEntry annotations and Kotlin Symbol Processing. This generated type-safe factories that Dagger injected, removing the need for reflection-based boilerplate.
Engineers now navigate between screens with strongly-typed destination objects like navigateTo(VehicleDetailsDestination(...)). This gives them compile-time safety while keeping the modular architecture intact, which helps with build times.