Screens from the TransFollow logistics app
KMPComposeMigration
T

Taras Leskiv

9 min read - Mar 12, 2025

Is KMP Production Ready in 2025? A Real-World Migration Story

A recap of the GDG Lviv talks that I gave in March of 2025 (In Ukrainian). A short retrospective on rewriting TransFollow’s logistics app with Kotlin Multiplatform and shared UI.

As a mobile engineer on a six-person team, I needed to deliver an iOS version of TransFollow’s mature Android app without adding a dedicated iOS developers. We chose to rewrite the product with Kotlin Multiplatform and Compose Multiplatform with shared UI.

Six months later, this is the retrospective: the strengths, the weaknesses, and the rough edges of KMP in 2025.

Download TransFollow Drive on the App StoreGet TransFollow Drive on Google Play

The Good: Where KMP Works Well

If you come from an Android background, KMP feels natural and close to the metal instead of bridged.

  • One language everywhere: Kotlin across platforms with expect/actual instead of plugin layers.
  • Desktop target accelerates iteration: JVM desktop builds are fast for UI mocks and testing; Compose Hot Reload (experimental) shortens feedback loops.
  • Ecosystem is mostly there: Ktor, Coil, Koin, SQLDelight (plus Room KMP), and Sentry covered our needs.
  • Shared UI is practical: Compose Multiplatform delivered Material 3 on Android and its own canvas on iOS. Platform-specific components (MapView, Camera) slot in via UIKitView / AndroidView.

The Challenges

  • Fast-moving toolchain: Version bumps across Kotlin, Compose, KSP, and libraries can conflict.
  • iOS build times and memory load: Building the iOS framework is heavy; even an M1/32GB can hit limits on release builds.
  • Objective-C interop friction: KMP outputs Objective-C today, so generics and API names can be verbose from Swift, and CocoaPods/c-interop errors are noisy.

The Rough Edge (now improving)

Fleet felt unfinished—large downloads and limited previews. JetBrains is now doubling down on Android Studio and IntelliJ for KMP, and Canary builds ship stable previews.

Tips for a smooth migration

  • Write native code yourself: Define expect in common code; implement actual with platform APIs instead of depending on wrappers.
  • Master suspendCoroutine: Bridge callback-based native APIs (e.g., permissions) into coroutines cleanly using suspendCoroutine.
  • Use SQLDelight: Room supports KMP now, but SQLDelight’s generated code stayed sturdier for us.
  • Don’t force SwiftUI (yet): Sharing UI with Compose kept our small team fast; native UI can wait.

Verdict

KMP is production ready for small and mid-sized teams—especially if you already think in Kotlin. You move quickly, share most of the code (including UI), and keep developer satisfaction high. I would choose the same path again.

Slides from the talk

View the deck on SlideShare: kmp-state-in-2025-taras-leskiv-gdg-lviv-meetup-06-03-2025-pptx