Kotlin Multiplatform vs Flutter: choosing for a real product
I've shipped production apps with both. They solve different problems, and the wrong choice is expensive in ways that only show up in year two.
Every cross-platform debate online seems to be argued by people who picked one and never used the other in anger. I've done both in production: Flutter for a mobile-money super-app serving an entire market, and Kotlin Multiplatform inside a national carrier's self-care app where I also owned the iOS side. Here's how I actually decide.
They're not competing for the same job
Flutter shares everything, including the UI. It draws its own widgets on a canvas, so what you build appears identically on iOS and Android. Kotlin Multiplatform shares only the layers you choose — typically models, networking, validation and business rules — while the interface stays native SwiftUI on iOS and Compose on Android.
That single difference drives everything else. Flutter optimises for delivery speed across both platforms. KMP optimises for correctness of shared logic while protecting the native experience.
When I reach for Flutter
- The product is mostly forms, lists, flows and transactions — which covers a surprising share of real apps.
- You have one team and need both stores at once, on a deadline.
- Brand-led design that's intentionally the same everywhere, rather than platform-idiomatic.
- You want the whole thing in one language and one repository, with one release rhythm.
The YAS app is the clearest example I've worked on. Top-ups, data bundles, wallet transfers, bill payments, home fibre, gamified rewards — dozens of screens, nearly all of them shared logic wrapped in shared UI. Building that twice natively would have doubled the cost and halved the pace for very little user-visible benefit.
When I reach for Kotlin Multiplatform
- You already have healthy native apps and a rewrite is not on the table.
- The interface matters enough that platform idioms are a feature, not a detail.
- The business rules are complex and duplicating them is where your bugs actually come from.
- Separate iOS and Android teams need a shared contract rather than a shared codebase.
On the carrier app, the valuable thing wasn't saved UI work — it was that pricing rules, plan eligibility and usage calculations existed once. Those are the places where iOS and Android quietly disagree and support tickets are born.
The costs nobody puts in the pitch deck
Flutter's tax is the platform boundary. Anything deeply native — widgets, complex background work, a niche SDK, new OS features on day one — means a plugin, and sometimes writing that plugin yourself in Swift and Kotlin anyway. App size is larger. And you need at least one person who can debug both native shells when a build breaks.
KMP's tax is setup and tooling. The Gradle and iOS integration is more work than adding a dependency, the Swift-side ergonomics of Kotlin types take getting used to, and your iOS engineers need to be genuinely willing to read Kotlin. When that willingness isn't there, the shared module rots into a thing only one team touches.
A simple way to decide
Ask what you're actually trying to avoid duplicating. If it's screens, Flutter. If it's rules, Kotlin Multiplatform. If it's both and you're starting from nothing with a small team, Flutter will get you to market sooner and you can revisit later — it's a codebase, not a marriage.
The best architecture is the one your team can still move quickly in eighteen months from now.
One last note: whichever you pick, don't let the shared layer decide your product. Users don't know or care which framework you chose. They notice whether the app is fast, whether it works on a bad connection, and whether it does the thing they opened it for.