Strategic Guide to Migrating Legacy Android Apps from XML to Jetpack Compose
Article Summary
Getir's Android team learned the hard way: migrating millions of users from XML to Jetpack Compose isn't about rewriting screens. It's about avoiding the performance traps that come with mixing old and new.
This deep dive from Getir's engineering team chronicles their large-scale migration to Jetpack Compose in a production app serving millions of daily users. They share the architectural decisions, performance pitfalls, and team dynamics that shaped their 18-month transformation from legacy XML to modern declarative UI.
Key Takeaways
- Hybrid XML-Compose screens created state management hell and scroll performance nightmares
- Unstable List types in UiState forced entire product lists to recompose unnecessarily
- ImmutableList adoption and contentType keys cut recomposition counts by 90% in critical flows
- Team built shared Compose component repo before migrating screens to prevent duplicate work
- A/B tested new Compose screens with user segments to catch issues before full rollout
The winning strategy was strict avoidance of embedded hybrid patterns and architectural cleanup before any Compose migration, not gradual screen-by-screen rewrites.
About This Article
Getir's codebase used old VIPER patterns and XML view-binding where ViewModels were tightly coupled to the view layer. This created inconsistent screen architectures that didn't work well with Compose's reactive state model without major refactoring.
Eren Karaboga's team built a custom Gradle configuration that enabled Compose for specific modules from one place. It automatically activated buildFeatures.compose and added dependencies like Compose BOM, Material3, and design system components without repetition.
The Gradle setup prevented manual configuration mistakes across modules and allowed teams to migrate gradually. New modules only needed a central list update instead of individual setup, which made it easier for teams to start using Compose.