Key Takeaways
- Never attempt a full rewrite. The incremental, screen-by-screen approach is the only reliable migration strategy for production Android apps. Google’s own apps, including Google Maps and Google Play, migrated to Compose incrementally.
- Start with new features. Every new screen should be written in Compose from day one. This gives your team Compose experience while delivering immediate value without touching existing code.
- ComposeView is your best friend. Android’s interoperability layer lets you embed Compose components inside existing XML layouts and vice versa. This is the foundation of an incremental migration.
- Migrate leaf screens first. Settings pages, profile screens, and static content screens have the fewest dependencies and are safest to migrate. Save complex screens with deep Fragment dependencies for last.
- Test coverage before migration is non-negotiable. If your existing screens do not have UI tests, write them before migrating. The tests become your safety net for verifying that the Compose version behaves identically to the XML version.
When I started building Android apps in 2009, XML layouts were the only option. I have written thousands of layout files over the years. Fragments, RecyclerView adapters, ConstraintLayout hierarchies, and custom views these tools served us well for over a decade. But Jetpack Compose has changed the equation entirely, and in 2026, it is clear that Compose is not a passing trend. It is the modern Android development standard.
The challenge is that most production Android apps were not built yesterday. They have years of XML layouts, complex Fragment navigation stacks, and deeply embedded View-based patterns. Migrating to Compose is not a weekend project. But it does not need to be a terrifying one either.
This guide walks through the incremental migration strategy that I have used and recommended across multiple production applications. No full rewrites. No big-bang migrations. Just a practical, low-risk path from XML to Compose that keeps your app stable throughout the process.
Why Migrate to Jetpack Compose at All?
Before investing in migration, the business case needs to be clear:
| XML Layouts (Legacy) | Jetpack Compose (Modern) |
| Separate layout XML files + Kotlin binding code | UI defined directly in Kotlin — single source of truth |
| Manual state synchronisation (observers, callbacks) | Declarative state management — UI recomposes automatically when data changes |
| Verbose boilerplate (findViewById, ViewBinding, adapters) | Significantly less boilerplate — Google reports up to 50% code reduction |
| Difficult to preview without running the app | Composable Previews in Android Studio — see UI changes instantly |
| Tight coupling between UI logic and lifecycle | Composables are functions — easier to test, reuse, and reason about |
The productivity gain is real and measurable. Teams I have worked with report 30–50% faster UI development in Compose once they pass the initial learning curve. The official Compose documentation from Google provides detailed migration guidance alongside the API reference.
The Migration Strategy: Incremental, Not Big-Bang
The single most important rule of Compose migration: never attempt a full rewrite. Migrate incrementally, screen by screen, component by component.
Phase 1: New Features in Compose Only (Weeks 1–4)
Before touching any existing code, establish a simple rule: every new screen and feature is built in Compose. This achieves two things simultaneously. First, your team gains hands-on Compose experience on real features, not tutorial exercises. Second, new code is already in the target architecture, reducing future migration scope.
Set up your project for Compose by adding the Compose BOM (Bill of Materials) to your build. gradle. This ensures all Compose libraries use compatible versions. Define your theme, typography, and colour palette in Compose early. This becomes the design system that all future Compose screens share.
Phase 2: Embed Compose in Existing XML Screens (Weeks 4–8)
Android’s interoperability APIs make this possible. ComposeView lets you embed Compose composables inside existing XML layouts. This is the key to incremental migration.
Start by replacing isolated UI components within existing screens. A static card, a list item, a header section. These are self-contained components that can be rewritten in Compose without affecting the surrounding XML layout. The existing Fragment or Activity continues to function normally. The Compose component renders inside it through ComposeView.
Phase 3: Migrate Complete Screens, Leaf First (Weeks 8–16)
Once your team is comfortable with Compose and interop, begin migrating complete screens. Start with leaf screens that have the fewest dependencies on other parts of the app:
- Settings and preferences screens
- Profile and account pages
- Static content screens (about, terms, help)
- Simple list/detail screens with straightforward data flows
Save complex screens for later screens with deep Fragment back stack management, complex RecyclerView implementations with multiple view types, or screens tightly coupled to legacy navigation patterns. These require more careful planning.
Phase 4: Migrate Navigation (Ongoing)
Navigation is typically the last major system to migrate. Moving from Fragment-based navigation to Compose Navigation is a significant architectural change. Do this gradually by keeping your existing navigation graph and replacing individual destination Fragments with Compose screens one at a time.
Common Mistakes That Cause Migration Failures
1. Trying to Migrate Everything at Once
The most common failure mode. A team decides to “rewrite the whole UI in Compose,” and three months later, they have a half-migrated app that is broken in both systems. Incremental migration is slower per screen but dramatically faster overall because each step is stable and shippable.
2. Migrating Without Test Coverage
If your existing XML screens do not have UI tests, write them before you start migrating. These tests become your verification mechanism: run the tests against the XML version, migrate to Compose, and run the same tests to confirm identical behaviour. Without tests, you are relying on manual QA to catch regressions, which is slow and unreliable.
3. Ignoring State Management Architecture
XML-based UIs often manage state through a mix of callbacks, LiveData observers, and direct View manipulation. Compose requires a unidirectional data flow: state flows down, events flow up. If you port XML code directly to Compose without restructuring the state management, you end up with Compose code that fights against its own framework.
4. Over-Optimising Recomposition Too Early
New Compose developers often worry about unnecessary recompositions from day one. In practice, Compose’s runtime is efficient enough that recomposition is rarely a performance problem for typical UI screens. Focus on correct behaviour first. Optimise recomposition only when profiling shows a measurable issue.
What This Means for Founders and Product Leaders
If you are managing a product with a legacy Android codebase, the migration decision is not purely technical. It is a business investment. The cost of maintaining a legacy codebase increases every year as fewer developers want to work with XML layouts, and as Google’s tooling increasingly favours Compose.
The incremental approach means you do not need to stop feature development. Your team ships new features in Compose while gradually modernising existing screens in the background. The investment pays for itself through faster development velocity, easier hiring, and lower maintenance costs over time.
Lessons from the Migration Trenches
Having guided multiple production apps through this process, here is what I know for certain:
The first screen is the hardest. Your team is learning Compose, setting up the build configuration, defining the design system, and figuring out the interop patterns. Allow extra time for this. After the first three screens, the team hits a rhythm, and subsequent migrations go dramatically faster.
Compose is worth the investment. The productivity gains, the improved testability, and the developer satisfaction are all real. But only if the migration is done incrementally and with discipline. A failed migration attempt is worse than staying on XML, because you end up with a fragmented codebase that has the worst of both worlds.
If your team is making this transition and needs experienced guidance, working with developers who have deep Android and mobile development experience can save months of trial and error. The patterns for a successful migration are well-established. The biggest risk is not knowing them before you start.
For the full context of how Android development has evolved to this point, my Android development history from 2009 to 2026 traces the complete journey from Eclipse and XML to Kotlin and Compose.



