# Migrating a Real Android App to Kotlin Multiplatform 1/4 -- Before the Migration

DevFeed: [Migrating a Real Android App to Kotlin Multiplatform 1/4 -- Before the Migration](<https://devfeed.tech/articles/migrating-a-real-android-app-to-kotlin-multiplatform-1-4-before-the-migration-107101.md>)

Original publisher: [Read original article](<https://proandroiddev.com/migrating-a-real-android-app-to-kotlin-multiplatform-1-4-before-the-migration-8b1d16f68747?source=rss----c72404660798---4>)

Author: Daniel Voko

Published: 2026-10-29T17:33:38Z

Content type: article

Language: en

Sources: [ProAndroidDev](<https://devfeed.tech/sources/proandroiddev-medium.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Android](<https://devfeed.tech/topics/android.md>), [Jetpack Compose](<https://devfeed.tech/topics/jetpack-compose.md>), [compose-multiplatform](<https://devfeed.tech/topics/compose-multiplatform.md>), [CI/CD](<https://devfeed.tech/topics/cicd.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [android-app-development](<https://devfeed.tech/tags/android-app-development.md>), [androiddev](<https://devfeed.tech/tags/androiddev.md>), [app](<https://devfeed.tech/tags/app.md>), [architecture](<https://devfeed.tech/tags/architecture.md>), [best-practices](<https://devfeed.tech/tags/best-practices.md>), [bike](<https://devfeed.tech/tags/bike.md>), [browser](<https://devfeed.tech/tags/browser.md>), [case-study](<https://devfeed.tech/tags/case-study.md>), [code](<https://devfeed.tech/tags/code.md>), [compose](<https://devfeed.tech/tags/compose.md>), [compose-multiplatform](<https://devfeed.tech/tags/compose-multiplatform.md>), [core](<https://devfeed.tech/tags/core.md>), [dagger](<https://devfeed.tech/tags/dagger.md>), [data](<https://devfeed.tech/tags/data.md>), [domain](<https://devfeed.tech/tags/domain.md>), [feature](<https://devfeed.tech/tags/feature.md>), [ios](<https://devfeed.tech/tags/ios.md>), [jetpack](<https://devfeed.tech/tags/jetpack.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-multiplatform](<https://devfeed.tech/tags/kotlin-multiplatform.md>), [migration](<https://devfeed.tech/tags/migration.md>), [multiplatform](<https://devfeed.tech/tags/multiplatform.md>)

## AI overview

BikeHub moved from native Android to Kotlin Multiplatform while keeping Android releasable at every step; about 84% of its Kotlin now lives in commonMain, with Android, iOS and WebAssembly targets. The migration benefited from early choices of KMP-compatible Ktor Client, Koin and SQLDelight, so networking, dependency injection and persistence mostly moved rather than needing replacement. Modularization provided a module-by-module migration order, limited failures to individual modules and made it practical to pause between releases. Android-specific code was pushed behind interfaces at platform boundaries, and the iOS app was kept to a thin Swift entry point and platform wiring. The author says they would add another target to CI as soon as the first module is converted, since Android-only code can compile in commonMain while still failing on other platforms; smaller, single-responsibility core modules would also have saved time.

## Source excerpt

BikeHub is KMP app that runs on Android, on iOS and in the browser via WebAssembly. It started as native Android. Around 84 percent of its Kotlin code lives in commonMain. At no point during the migration did the Android app stop being releasable. This isn't a story about a heroic rewrite. The real story is less dramatic and, I think, more useful: the migration was easier than it could have been because of choices made long before it started. How much a platform shift hurts is decided largely by architectural decisions made years earlier, often for entirely different reasons. This series isn't a KMP tutorial either. This is a case study of a real app that already had users, history and assumptions baked into its code: what moved easily, what hurt, and what I'd do differently. Part 1 covers the foundations. Where it started BikeHub is a bike maintenance tracker. It pulls your mileage from Strava, tracks wear on parts like chains, cassettes and brake pads, and tells you when something is due for a service. It is a side project, that has its own story. Initially started to try out new libraries and best practices and was for an audience of one. Later it turned into something I wanted to release to wider audiences. It started as a native Android app, split into 24 feature modules and 14 core modules (before the start of the migration). Today it has both more feature modules and more granularized core modules: Where it started Kotlin, Jetpack Compose, a layered architecture, UDF in the presentation layer, and a reasonable number of modules make it a fairly standard modern Android stack. What made the difference later wasn't how modern each piece was, but how portable it turned out to be. Choices made before the migration Ktor Client and Koin were in the app from day one, and both already supported Kotlin Multiplatform. Ktor Client is something I prefer over Retrofit, and Koin is something I prefer over Dagger. When the data and domain layers moved to shared code, the net