Kotlin Multiplatform vs Compose Multiplatform: How We Decide What to Use
We first started experimenting with Kotlin Multiplatform (KMP) and Compose Multiplatform (CMP) when a few of our clients began asking how we could help speed up development without losing app quality.

Our team is already strong in native iOS and Android development, so Flutter or React Native didn’t make much sense for us. But Kotlin’s cross-platform options were worth exploring, especially since we could stay in the Kotlin ecosystem while gradually increasing code sharing across projects.
Here’s a quick breakdown of what we’ve learned so far after building and maintaining two KMP apps and one full CMP app in production, including some things we wish we knew earlier.
Why We Started With KMP?
When it comes to KMP, our experience was a roller coaster, but in a good way. At the moment we decided to give it a try, we had to decide whether to share only the networking layer or the entire business logic, including the view models.
We went for it.
We decided to share the entire business logic layer, including ViewModels, and even pushed further by sharing assets and strings between the platforms. That’s where things got, well, interesting.
The Bumpy Start With KMP
It was mostly due to Kotlin-Swift interoperability with the combination of SwiftUI for the UI part of our Kotlin Multiplatform apps. The thing is that Kotlin code gets compiled to Objective-C wrappers, so even with a couple of different libraries we use to observe the changes from the shared view models in our SwiftUI views, we had to adjust the libraries and create our own wrappers to do it the right way.
Then came a game changer: Google exposed the Android ViewModel to KMP. That cleaned up a lot of the mess and made integration with SwiftUI way smoother.
We were also building and shipping features while figuring this out, so yeah, it was a bit chaotic. But looking back, it was totally worth it. The performance stayed solid, and we saved a lot of time down the road by not duplicating core logic across platforms.
When We Switched to CMP?
Then came a different kind of project: a client wanted to redesign their KMP-based app from the ground up. Since we were already sharing logic, the next logical step was: why not share the UI too?
That’s when we started digging into Compose Multiplatform.
It made a lot of sense for this case:
- We could move much faster
- We didn’t have to duplicate UI work
- And it was a great chance to see how CMP holds up in real production
We got the project up and running in Android Studio Compose Multiplatform, which gave us one shared codebase for UI and logic.
But CMP came with its own set of problems.
CMP Navigation on iOS = Painful (But Fixable)
Our biggest challenge was navigation on iOS. The app needed to feel native, and that meant swipe-back gestures and proper transition animations.
We tried everything: Compose navigation, Voyager, custom hack, but nothing really nailed it.
In the end, we kept native navigation on both iOS and Android and used Compose screen wrappers inside those native containers. That turned out to be the perfect combo.
It looked and felt native, but we were still writing shared UI using Compose and we managed to ship the updated app in just 1.5 months.
Pros and Cons: Kotlin Multiplatform vs Compose Multiplatform
Based on our experience building and maintaining both KMP and CMP apps, I want to share with you some of the pros and cons of what each approach brings to the table and what to watch out for.
Kotlin Multiplatform (KMP)
Pros:
- More flexibility, since you’re writing fully native UIs for iOS and Android, including custom navigation flows
- Still faster than full native development, because you can share your entire business logic layer, including ViewModels
- You get full access to platform-native libraries without weird workarounds
Cons:
- Sharing things like strings and assets takes extra effort and setup
- Since the UI isn’t shared, development takes longer, especially when you’re juggling multiple cross-platform mobile apps at once
- Some boilerplate is still needed for SwiftUI interoperability, especially early on
Compose Multiplatform (CMP)
Pros:
- Much faster than KMP because you’re also sharing the UI; a big win for fast-moving projects or MVPs
- You can share even advanced features like QR code scanning, social logins, or deep links, thanks to Compose’s expect/actual structure
- If you want, you can still keep native navigation on both platforms and just wrap Compose screens, which is how we made it feel 100% native on iOS
Cons:
- Out of the box, Compose Navigation doesn’t support iOS swipe-back gestures, so you’ll need a workaround if your app depends on that native feel
- Getting started with expect/actual can be tricky; it requires understanding both iOS and Android internals, which can slow things down for teams that lean heavily one way
- If you’re new to CMP, a good CMP template can save you a ton of time and help avoid common mistakes, especially with architecture, navigation, and platform-specific integrations.
How We Work With CMP Now?
These days, we usually kick off new projects with a Kotlin Multiplatform base. It gives us a clean architecture with shared business logic right from the start. It’s flexible enough to support native UIs when needed.
But when we know the project would benefit from even faster development, especially when we’re working under tight deadlines or delivering for multiple client tracks, we layer in Compose Multiplatform for the UI as well.
This setup lets us share everything from ViewModels to full screens, all while keeping a native feel where it matters most, like navigation, animations, or platform-specific features.
We’ve also started using a CMP template that makes the whole process way easier.
Instead of spending days on boilerplate, we have a CMP project ready to go almost instantly. The template already includes things like:
- Shared architecture that’s clean and scalable
- Examples of how to wrap Compose screens in native containers (super handy for iOS)
- Expect/actual implementations for common mobile features
- Navigation patterns that just work, even when you keep native navigation
It’s honestly worth especially for teams who are just getting into cross-platform app development with Compose. You don’t need to have years of CMP experience or be an expert in both Android and iOS to build something solid.
We’ve used this approach for projects in finance, wellness, and e-commerce industries where timelines are tight, and the apps need to feel smooth and polished across platforms.
If you’re stretched on capacity but want to move fast without sacrificing quality, starting with a good CMP template is the best shortcut we’ve found.
Final Thoughts
If you’re like most companies we work with, you're juggling multiple apps, your devs are at full capacity, and critical deadlines are approaching fast, KMP and CMP can genuinely help, but choosing between them depends on your goals:
- Need full flexibility and tight control? Go KMP.
- Need to move fast with shared UI? Go CMP.
- Need both? You can mix and match.
The key is to start with a setup that doesn’t slow you down, works with your team’s strengths, and is easy to maintain in the long run.
If you’re thinking about trying CMP, I highly recommend starting with a solid CMP template. It makes everything easier, from navigation to architecture, and gives you a head start without the usual CMP headaches.
Plus, if you’ve been debating Compose Multiplatform vs Flutter, this setup lets you stay in the Kotlin ecosystem, support native features more easily, and avoid switching to Dart just to share UI.
Have questions or want to talk? You can always hit me up.
Need Experienced Devs to Build Your App?
