What Is Kotlin Multiplatform?
Kotlin Multiplatform (KMP) compiles Kotlin for several targets: the JVM for Android, Kotlin/Native for iOS, and JavaScript or WebAssembly for the web. Unlike Flutter or React Native, KMP does not force a shared UI. You decide how much to share, from one networking module to the entire app.
KMP has been stable since late 2023, and Google officially supports it for sharing business logic between Android and iOS. As of October 2026 the latest stable Kotlin release is 2.4.21, with 2.5.0 planned for December 2026.
What to Share and What to Keep Native
| Layer | Typically shared? | Notes |
|---|---|---|
| Domain models and business rules | Yes | Pure Kotlin, easiest win |
| Networking and serialization | Yes | Ktor + kotlinx.serialization |
| Local storage and caching | Yes | SQLDelight, Room, DataStore |
| ViewModels and state | Often | Jetpack ViewModel and Lifecycle support KMP |
| UI | Optional | Native UI or Compose Multiplatform |
| Platform APIs (camera, payments, widgets) | Rarely | Wrap behind interfaces |
A common starting point is "shared logic, native UI": Jetpack Compose on Android, SwiftUI on iOS, one Kotlin module underneath.
Compose Multiplatform
Compose Multiplatform (CMP) is JetBrains' declarative UI framework based on Jetpack Compose. Compose Multiplatform 1.8.0, released on May 6, 2025, declared iOS support stable. As of October 2026, the 1.12 line is current (1.12.2 was released in October 2026).
| Platform | KMP core | Compose Multiplatform |
|---|---|---|
| Android | Stable | Stable |
| iOS | Stable | Stable |
| Desktop (JVM) | Stable | Stable |
| Web (Kotlin/Wasm) | Beta | Beta |
CMP draws its own UI on iOS instead of using UIKit components, similar to Flutter. You can mix approaches: host a Compose screen in a SwiftUI app, or embed native iOS views inside Compose.
Project Structure
A typical KMP project has a shared module with source sets per platform:
shared/
src/commonMain/ // code for all platforms
src/androidMain/ // Android-specific implementations
src/iosMain/ // iOS-specific implementations
androidApp/ // Android application
iosApp/ // Xcode project
expect/actual
When common code needs a platform API, declare an expect in commonMain and provide an actual in each platform source set. Expect/actual functions and properties are stable; expect/actual classes are still Beta. The official guidance is to prefer an interface plus a factory function:
// commonMain
interface Platform { val name: String }
expect fun getPlatform(): Platform
// iosMain
actual fun getPlatform(): Platform = object : Platform {
override val name = UIDevice.currentDevice.systemName()
}
Key Libraries
| Need | Library |
|---|---|
| Async and streams | kotlinx.coroutines (suspend, Flow) |
| JSON | kotlinx.serialization |
| HTTP | Ktor client (OkHttp engine on Android, Darwin on iOS) |
| SQL database | SQLDelight or Room (KMP) |
| Key-value storage | DataStore (KMP) |
| Dependency injection | Koin |
| Date and time | kotlinx-datetime |
| Architecture | Jetpack ViewModel, Lifecycle, Navigation (KMP versions) |
Before adding a dependency, check that it publishes artifacts for every target you use, including iosArm64 and iosSimulatorArm64.
iOS Integration
The shared module compiles to an Apple framework. Integrate it directly through a Gradle build phase in Xcode, or distribute it as an XCFramework via Swift Package Manager.
The Objective-C Bridge
By default, Kotlin exposes its API to Swift through Objective-C headers. Some Kotlin features translate poorly: sealed classes do not become Swift enums and Flow needs wrappers.
SKIE (by Touchlab) is a popular Gradle plugin that improves this: sealed classes become exhaustive Swift enums, suspend functions become async, and Flows become AsyncSequence. SKIE support for new Kotlin versions can lag, so check compatibility before upgrading Kotlin.
Swift Export
Swift export generates Swift APIs directly from Kotlin, without the Objective-C layer. As of October 2026 the official docs list it as Alpha: it requires direct integration, has limitations around generics, and breaking changes are expected. The Kotlin roadmap lists moving it to Beta. Evaluate it, but keep the default bridge for production for now.
KMP vs Flutter vs React Native
| Kotlin Multiplatform | Flutter | React Native | |
|---|---|---|---|
| Language | Kotlin | Dart | JavaScript / TypeScript |
| UI | Native or Compose Multiplatform | Own rendering engine | Native components |
| What you share | Anything from one module to everything | Usually the whole app | Usually the whole app |
| Adopt in an existing native app | Incremental, module by module | Possible, less common | Possible, less common |
| Android output | Regular Kotlin/JVM code | Dart runtime + engine | JS runtime + native modules |
| iOS team experience | Swift calls a Kotlin framework | Mostly Dart | Mostly JS/TS |
When to Choose KMP
- You already have a Kotlin Android app and want to reuse its logic on iOS.
- You want native UI on each platform but one source of truth for business rules.
- Your team has strong Kotlin skills; Swift developers can still own the iOS UI.
- You need deep platform integration that a shared UI layer would make harder.
For a brand-new app from a small team that wants one UI codebase, Flutter or React Native can be simpler.
Migrating an Existing Android App
- Isolate pure Kotlin code. Move models, validation and use cases into a
sharedmodule with no Android imports. - Replace Android-only dependencies. Swap Retrofit for Ktor, Gson or Moshi for kotlinx.serialization,
java.timefor kotlinx-datetime, and move persistence to Room KMP or SQLDelight. - Ship one iOS feature. Use the shared module for a single iOS flow and check build times, binary size and Swift API ergonomics.
- Expand gradually. Share repositories and ViewModels next; consider Compose Multiplatform screens later.