One developer is currently available to jump onto a project!

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

This Is How Our Engineers Build KMP Apps

Here's the production-ready Kotlin Multiplatform template they built. Clean architecture, shared business logic, Firebase, Ktor.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

This Is How Our Engineers Build CMP Apps

Here's the production-ready Kotlin Multiplatform template they built. Clean architecture, shared business logic, Firebase, Ktor.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Migrating From KMP to CMP: 10,000 Compile Errors Later

Category:
Tech & Insights
Author:
Andjela Sokolovic Antic
Date:
July 15, 2026
Migrating From KMP to CMP: 10,000 Compile Errors Later

Migrating Client’s App from Kotlin Multiplatform to Compose Multiplatform

Migrating from Kotlin Multiplatform (KMP) to Compose Multiplatform (CMP) sounds straightforward on paper. Your business logic is already shared, Jetpack Compose is familiar to Android developers, and Compose Multiplatform promises a single UI for Android and iOS.

In reality, the migration is rarely just a matter of moving files around.

Recently, I migrated a real Kotlin Multiplatform application to Compose Multiplatform. It wasn't a massive enterprise project, but intentionally chosen as a smaller production application with around a dozen screens, shared business logic, and separate Android and iOS UIs.

I was also working on the original KMP project, meaning I knew the architecture inside out. If there was ever a project that should have been an "easy migration," this was it.

Except it wasn't.

After more than two weeks of development, over 10,000 compile errors, countless architectural decisions, and plenty of help from AI, we successfully finished the migration.

This isn't another generic Compose Multiplatform tutorial, but a practical look at what happens when you migrate an existing Kotlin Multiplatform application, and what I'd do differently today.

Why We Decided to Migrate from Kotlin Multiplatform to Compose Multiplatform

So here's where we started: our original project was already sharing business logic between Android and iOS. Repositories, use cases, networking, domain models, all of it, shared.

Pretty solid setup, right?

Except for one thing: the UI.

Every single feature still had to be built twice. Once in Jetpack Compose for Android, once in SwiftUI/UIKit for iOS. This approach worked, but maintaining two separate UI implementations can become expensive quickly. Every bug fix and every new feature meant doing the same work twice.

That's the problem Compose Multiplatform actually solves.

Instead of stopping at business logic, you can share your presentation layer too. That means way less duplicated work across platforms, without giving up native performance or native APIs where you actually need them.

For teams building enterprise mobile products, here's what that looks like in practice:

  • Faster feature delivery
  • Less duplicated code
  • Easier maintenance
  • A more consistent user experience
  • Lower long-term development costs

If you're still evaluating whether Compose Multiplatform is the right architectural decision, check out our Kotlin Multiplatform for Enterprise guide to understand where it delivers the biggest ROI.

Step 1: Migrating the Shared Business Logic

Instead of trying to convert the existing project piece by piece, I started a fresh Compose Multiplatform project and copied over everything that was still relevant.

Repositories came first, then use cases, then models.

Since the business logic was already multiplatform, most of the migration was surprisingly straightforward.

The first real obstacle appeared almost immediately:

Firebase.

Our application relied heavily on Firebase as its backend.

While Firebase support for Kotlin Multiplatform has improved significantly over the years, it's still far from being a plug-and-play experience. Many services still require platform-specific configuration, and documentation isn't always as comprehensive as you'd expect.

Like many KMP teams, we used GitLive Firebase, which has become the de facto standard for Firebase Multiplatform support.

It works, but it still requires significantly more setup than native Android development.

Rather than getting stuck on infrastructure early on, I made a decision that paid off later: I temporarily mocked all Firebase endpoints so I could keep migrating the rest of the application without waiting on native integration work (more on why that mattered further down).

Once the business layer was migrated, both Android and iOS applications compiled successfully, even though the UI still consisted of nothing more than a "Hello World" screen.

Starting a new Kotlin Multiplatform project?

Download the same Kotlin Multiplatform project template our developers use internally to build production-ready applications faster.

Step 2: ViewModels Were a Pleasant Surprise

This was the part I expected to hate.

Back when we originally built our KMP application, multiplatform ViewModels were awkward. The standard solution was MOKO MVVM. It worked, but it introduced additional abstractions, platform-specific behavior, and a considerable amount of boilerplate.

I fully expected the migration to involve replacing ViewModels one by one.

Instead, I discovered something much better: Compose Multiplatform now supports Jetpack Compose ViewModels directly.

No additional third-party library, custom wrappers, or platform bridges.

Most of my ViewModels looked almost identical to their Android implementations.

Deleting hundreds of lines of MOKO boilerplate was probably the most satisfying part of the entire migration.

For the first time, the project actually felt simpler than the original KMP implementation.

Step 3: The UI Migration That Generated More Than 10,000 Compile Errors

Then came the part I'd been avoiding.

The UI.

Our application wasn't visually complex, only around twelve screens. Mostly standard Material components. The problem wasn't complexity; it was coupling. Almost every composable depended on another composable, shared resources, navigation, or Android-specific behavior.

Without much planning, I copied the entire Android UI from the original project into commonMainin one go, thinking it would be faster to fix everything in the same place.

Instantly, I got 10,000+ compile errors.

Looking back, this was easily my biggest mistake, and I'll come back to why in the "What I'd Do Differently" section. For now, here's how those errors broke down.

Every error fell into one of three categories:

Easy

  • Missing imports
  • Changed package names
  • Unresolved dependencies

Medium

Libraries that worked perfectly in KMP were deprecated, replaced, or no longer recommended for Compose Multiplatform.

Finding modern alternatives took time.

Hard

Some parts of the code were simply Android.

  1. Permissions.
  2. Lifecycle behavior.
  3. Context usage.
  4. Platform APIs.

Those pieces had to be pulled out into expect/actual implementations, each with its own dedicated iOS counterpart.

The hardest part wasn't fixing individual errors. Those come and go, you expect that.

The real problem was losing sight of progress. At some point I realized I wasn't building features anymore. I was just fighting compiler errors, day after day.

For nearly two weeks, "success" meant getting Android to compile. That was it. That was the win.

Not exactly a great feeling.

One Unexpected Win

Not everything was painful. One pleasant surprise was resource management.

Unlike older KMP projects that often relied on third-party libraries for shared resources, Compose Multiplatform allows sharing strings, images, and other assets much more naturally.

Migrating resources took minutes instead of hours. Sometimes it's the small wins that keep a migration moving.

AI Became My iOS Developer

One misconception I still see online is that Android developers can build Compose Multiplatform applications with little or no iOS experience. While that's technically possible, I don't think it tells the whole story.

From my experience, the stronger your iOS foundation is, the smoother your Kotlin Multiplatform to Compose Multiplatform migration will be. Compose Multiplatform allows you to share significantly more code than traditional KMP projects, but you're still building applications that need to behave like native iOS apps. At some point, you'll inevitably run into platform-specific APIs, lifecycle differences, dependency management, or UI behaviors that require an understanding of how iOS works under the hood.

I don't consider myself an iOS developer, and that became obvious very quickly.

If you want to know about Why iOS Teams Become the Bottleneck of KMP Development, you can read the story from real experience here.

Throughout the migration, I constantly found myself facing problems that weren't really related to Compose Multiplatform itself. They were iOS problems. Questions like "What's the equivalent of this Android API?", "Why does this work on Android but fail on iOS?", or "Should this be implemented in commonMain or moved into an expect/actual implementation?" became part of my daily workflow.

In the past, solving those questions would have meant spending hours reading documentation, browsing Stack Overflow, searching GitHub issues, or watching conference talks. About halfway through the migration, I decided to try something different: I brought Claude Code into the project. Not to generate the application for me or blindly write production code, but to act as a senior iOS teammate who was always available to explain why something worked.

I treated Claude as an AI coding agent and a pair programming partner rather than a replacement for software engineering. I would first solve the problem on Android, where I was confident in the implementation, and then use that code as context while asking Claude to help me produce the equivalent iOS implementation. Instead of simply accepting generated code, I kept asking follow-up questions until I understood the reasoning behind every architectural decision.

That approach completely changed how productive AI-assisted development felt. Rather than replacing my knowledge, it filled the exact gaps that were slowing me down.

Once Claude had enough context about our architecture, coding conventions, and project structure, it became surprisingly effective. It generated expect/actual implementations, explained iOS-specific APIs, suggested Compose Multiplatform alternatives to deprecated libraries, and even helped troubleshoot dependency issues that would have taken me much longer to investigate manually.

This was my first experience seriously building software with AI, and I understand why so many developers are now searching for terms like AI coding, AI pair programming, AI coding agents, Claude Code vs GitHub Copilot, and how to use AI for software development. The biggest productivity gains didn't come from asking AI to write more code, but from using it to remove the blockers that interrupted my development flow.

Looking back, waiting until the second half of the migration to introduce AI was one of my biggest mistakes.

If I started another Compose Multiplatform migration tomorrow, I'd integrate AI into the project from day one. With the right context, clear architectural boundaries, and an experienced developer reviewing every change, AI coding agents can easily save several days of development time, especially when working across platforms where your expertise isn't equally strong.

Want to see more detailed examples in video form?
Check out our YouTube channel
Check out our YouTube channel
Youtube Logo

Integrating Native iOS Dependencies

The business logic had already been migrated. The ViewModels were working. The shared Compose Multiplatform UI was finally compiling on both platforms.

The last major obstacle had nothing to do with Compose Multiplatform itself. It was integrating native iOS dependencies, and this is where mocking Firebase early on paid off. Because I'd deferred the real integration until the architecture and shared UI were stable, I could give this problem my full attention instead of debugging it alongside everything else.

Firebase setup alone took more than four hours.

Coming from Android, my instinct was to use Swift Package Manager. It felt like the natural choice and the modern replacement for CocoaPods. Everything looked correct, the packages downloaded successfully, Xcode recognized them, dependency resolution completed without errors, and all paths appeared to be configured correctly.

Yet the application simply refused to build.

There was no obvious indication of what was actually wrong. No missing dependency, or clear compiler message pointing me in the right direction. Just a project that looked correctly configured but continuously failed during compilation.

After trying multiple approaches and spending far more time than I expected, I eventually switched to CocoaPods. With plenty of help from Claude Code to troubleshoot the configuration and compare different setup options, the project finally built successfully.

To this day, I still can't say with complete confidence what the root cause was. Maybe Swift Package Manager and CocoaPods were both introducing the same packages. Maybe there was a subtle configuration conflict inside the Xcode project. Maybe I simply lacked enough iOS experience to recognize the problem immediately.

And that's exactly the lesson.

The biggest delays during a Kotlin Multiplatform to Compose Multiplatform migration rarely come from writing shared Kotlin code. They come from platform-specific integrations that behave differently on Android and iOS, especially when you're working with services like Firebase Multiplatform, native SDKs, or third-party Kotlin Multiplatform libraries. Those are the problems that usually aren't covered by official documentation because every project has a different combination of dependencies, build configuration, and native integrations.

Looking back, this experience reinforced something I now believe every team planning a Compose Multiplatform migration should know: migrating shared code is only half the job. Successfully integrating the native ecosystems around that shared code is where the real complexity begins, and where experience can save days, or even weeks, of development time.

What I'd Do Differently Today

If I had to migrate another Kotlin Multiplatform project tomorrow, I would change several things.

1. Never Migrate Everything at Once

If I could go back and change one decision, it would be this one.

As I mentioned earlier, copying the entire Android UI into the new project in one pass created more than 10,000 compile-time errors overnight. At first it felt like progress, because all the code was sitting in the right project. In reality, I'd created a giant puzzle where every solved error revealed three new ones somewhere else. It became genuinely hard to tell whether the project was moving forward or whether I was just spending my days chasing compiler output.

Next time, I'd take a much more incremental approach: I would migrate one feature at a time, make sure it works on both Android and iOS, and only then move on to the next part of the application. Smaller migration batches create much shorter feedback loops, make debugging significantly easier, and reduce the overall risk of introducing architectural issues that are difficult to trace later. It may not feel as fast in the beginning, but for a real Compose Multiplatform migration, it's a far more sustainable strategy.

2. Stabilize Android First

One decision I would absolutely make again is using Android as my reference platform throughout the migration.

Android is where I have the most experience, so whenever I encountered a problem, I first focused on getting the Android implementation working correctly. Once I knew the shared architecture behaved as expected, writing the iOS implementation became much easier. Instead of trying to solve problems on two unfamiliar fronts at the same time, I always had one stable platform I could rely on.

For Android developers moving to Compose Multiplatform development, I think this is one of the biggest advantages you already have. Treat Android as your foundation, validate your business logic and UI there first, and then focus on translating platform-specific behavior to iOS through expect/actual implementations where necessary. Having one stable reference point makes the entire migration process much less overwhelming.

3. Introduce AI Earlier

As I described above, I didn't bring Claude Code into the project until roughly halfway through, and that delay probably cost me several days. At the start, I wasn't convinced AI coding assistants were mature enough for a real production project, and I assumed I'd spend more time reviewing generated code than writing it myself. I couldn't have been more wrong.

The lesson isn't "let AI write the app." It's that having an always-available second opinion on iOS-specific questions, the kind of thing that used to mean an hour of documentation and Stack Overflow, removes exactly the interruptions that stall a migration. Next time, AI is part of the project from day one, not something I reach for once I'm already stuck.

The biggest productivity boost came from removing the constant interruptions that slowed down development. Instead of spending an hour reading documentation or searching GitHub issues, I could have an informed technical discussion, understand the problem, and continue building. That's why, if I started another Kotlin Multiplatform to Compose Multiplatform migration tomorrow, AI would be part of the project from day one.

It's also the approach we now follow when delivering our Compose Multiplatform development services. Rather than treating migration as a massive rewrite, we combine incremental migration, architectural reviews, platform-specific expertise, and AI-assisted development to help teams modernize existing Kotlin Multiplatform applications with significantly less risk and much faster delivery.

Should You Migrate Your Existing Kotlin Multiplatform Project?

The answer depends on your application.

Compose Multiplatform is production-ready enough for many commercial products, but that doesn't automatically mean every KMP project should migrate immediately.

Migration usually makes sense if:

  • Your team maintains separate Android and iOS UIs
  • Both platforms evolve together
  • Most new features require duplicated UI work
  • You're planning significant product development over the next few years
  • You want to reduce long-term maintenance costs

On the other hand, if your application is stable, receives only occasional updates, or depends heavily on platform-specific UI, migration may not provide an immediate return on investment.

Every architecture is different, that's why migration decisions should be based on technical analysis.

If you're unsure, our Kotlin Multiplatform Development Services team can review your architecture and help determine whether migration is worth the investment.

When It Makes Sense to Bring in Compose Multiplatform Experts

After finishing this migration, I don't think every team needs external help. Smaller applications can often be migrated successfully by an experienced in-house team with enough time to learn along the way.

Enterprise projects are different.

Large modular codebases, Firebase, native SDK integrations, authentication, analytics, CI/CD pipelines, and years of architectural decisions make migration much more than moving UI into commonMain. At that point, it becomes an architectural modernization project where the biggest challenges are rarely the shared Kotlin code, they're the platform-specific decisions that come with it.

If your team needs to move quickly without spending weeks on trial and error, bringing in experienced Compose Multiplatform developers can significantly reduce migration risk. And if you don't need a full outsourcing partner, you can simply hire dedicated Kotlin Multiplatform developers who integrate directly into your existing team and help accelerate the migration while keeping your delivery on track.

Frequently Asked Questions

Is Compose Multiplatform production-ready?

Yes. Compose Multiplatform has matured significantly and is already being used in production by companies building commercial mobile applications. Whether it's the right choice depends on your project's requirements and architecture.

How long does a KMP to Compose Multiplatform migration take?

It depends on the size of your application, third-party integrations, and UI complexity. Even relatively small projects can reveal unexpected challenges, especially around native dependencies.

Do I need to rewrite my shared business logic?

Usually not. If your existing Kotlin Multiplatform architecture is well-structured, most repositories, use cases, and domain logic can be migrated with minimal changes.

What's the biggest migration challenge?

Surprisingly, it often isn't Compose itself. Native integrations, platform-specific dependencies, and replacing outdated libraries tend to consume the most time.

Final Thoughts

When I started this Kotlin Multiplatform to Compose Multiplatform migration, I expected to spend most of my time rewriting UI.

Instead, I learned that successful migrations are much more about architecture, native integrations, and choosing the right migration strategy than simply moving code into commonMain.

Was it easy? Not at all.

Would I do it again? Absolutely.

Now that the migration is complete, the long-term benefits are already clear: a shared UI, less duplicated code, a cleaner architecture, and a development process where new features only need to be built once instead of twice.

If you're planning your own CMP migration, every project comes with its own challenges. Sometimes a quick architectural review can save weeks of unnecessary trial and error.

If you'd like a second opinion on your migration strategy, or need experienced Kotlin Multiplatform developers to help your team deliver faster, book a short technical call with Aetherius.

We'd be happy to review your project, answer your questions, and help you avoid the mistakes we made along the way!

Need Experienced Devs
to Build Your App?
Hire Us
Hire Us
CTO’s newsletter
Stay informed with the latest tech updates.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Want to know the price of your project development?
Calculate Costs Now
Calculate Costs Now

Let’s Understand Your Current Setup

Tell us more about the project needs