Articles / Technical
Kotlin Multiplatform vs React Native vs Flutter: Which Should You Choose?
If you're building a mobile app that needs to run on both Android and iOS, you'll face the cross-platform question early. React Native, Flutter, and Kotlin Multiplatform are the three dominant options. Each has genuine strengths and real trade-offs. Here's an honest comparison, without the framework tribalism.
Why cross-platform exists
Writing two fully separate native apps (one in Kotlin/Compose for Android, one in Swift/SwiftUI for iOS) means roughly double the code, double the bugs to fix, and double the effort to add a feature. For most teams and most budgets, that's not viable.
Cross-platform frameworks solve this by sharing some or all of the code between platforms. The trade-off is always some loss of native behaviour, performance ceiling, or platform-specific capability. The question is: which trade-off fits your situation best?
React Native
React Native, backed by Meta, lets you write your app in JavaScript or TypeScript using React patterns. It renders to native platform components via a bridge, so a React Native Button actually becomes a native Android or iOS button under the hood.
React Native works well when your team already knows JavaScript and React, when your app's UI maps cleanly to native components, or when you need a large ecosystem of ready-made libraries.
The challenges are real though. The bridge between JavaScript and native code has historically been a performance bottleneck for complex interactions and animations. "Feels native" is the aspiration but not always the reality; experienced mobile users notice the difference. Upgrades between React Native versions have been notoriously painful.
React Native is the pragmatic choice for JavaScript/web teams building mobile apps that don't push platform boundaries.
Flutter
Flutter, backed by Google, takes a different approach: it doesn't use native UI components at all. It draws everything itself using its own rendering engine (Skia, now Impeller). This means pixel-perfect consistency across Android, iOS, web, and desktop, but the UI elements aren't native widgets.
Flutter's language, Dart, is purpose-built for UI: it's fast, has sound null safety, and hot reload makes iteration quick. The ecosystem is strong and growing rapidly.
Flutter is the right choice when visual consistency across platforms is more important than native feel, when you want to target Android, iOS, and web from a single codebase, or when your team is willing to learn Dart.
The main trade-off: your app doesn't use native widgets, so it may feel slightly off to users familiar with platform conventions. App sizes tend to be larger. Dart is a new learning curve for most teams.
Kotlin Multiplatform
Kotlin Multiplatform (KMP) takes a fundamentally different approach to the others. Rather than replacing the native UI layer, it shares the logic underneath it. ViewModels, UseCases, repositories, Firebase integration, data models, and error handling, all written once in Kotlin and shared across Android and iOS. The UI remains native: Compose on Android, SwiftUI or Compose Multiplatform on iOS.
This means KMP apps are genuinely native on both platforms. There's no bridge, no custom rendering engine, no Dart runtime. The performance ceiling is the same as a native app, because at the UI layer it is a native app.
KMP is ideal when your team already writes Kotlin for Android, when your app has significant and complex business logic that would be painful to maintain in two languages, or when native platform behaviour matters, such as precise gesture handling, system integrations, or hardware features.
The trade-offs: the ecosystem is less mature than React Native or Flutter. Setting up a KMP project correctly requires more upfront knowledge. And you still need to write platform-specific UI, which means you need some iOS development familiarity.
KMP is not a replacement for native development; it's a way to share the expensive part (business logic) while keeping the valuable part (native UI) per platform.
Which one should you choose?
Start with your team's existing skills. Switching frameworks to build a product is a significant cost. If your team knows Kotlin, KMP is the natural path. If they know JavaScript and React, React Native makes sense. If they're starting fresh and visual consistency matters, Flutter is worth serious consideration.
- →Android-first team adding iOS → Kotlin Multiplatform. Shared logic is already in Kotlin.
- →Web/JavaScript team building mobile → React Native. Familiar patterns, large ecosystem.
- →Consistent cross-platform UI is the priority → Flutter. Owns the rendering pipeline.
- →Complex business logic on both Android + iOS → KMP. Write it once, test it once.
- →Android only, for now → Native Kotlin + Compose. No cross-platform overhead.
In summary
There is no universally correct answer. KMP is the most technically sound choice for teams with Kotlin experience building logic-heavy apps where native behaviour matters. React Native suits JavaScript teams well. Flutter wins when visual consistency matters more than platform conventions. Choose based on your team, your users, and the complexity of your domain logic, not on which framework has the most GitHub stars this month.
Building something in South Africa?
Black Arrows is a Johannesburg-based mobile app and software consultancy. If you're working through a decision like the ones in this article, a short conversation is usually the fastest way to get clarity.