Kotlin Multiplatform Cuts iOS and Android Boilerplate in Half

Mobile Development
Date:October 9, 2026
Topic:
Kotlin Multiplatform Cuts iOS and Android Boilerplate in Half
⏱ 3 min read

You're maintaining two codebases that do the same thing. Network layer, data models, business rules — duplicated across Kotlin and Swift. Every bug fix applied twice. Every feature tested twice. In 2026, Kotlin Multiplatform finally makes that waste optional.

What Changed in Kotlin 2.3

Kotlin 2.3 Multiplatform shipped three improvements that moved KMP from experiment to production default: 40% faster Native release builds, Swift export for idiomatic iOS APIs, and 13% smaller Wasm binaries. The compiler now emits Swift-compatible frameworks directly — no more awkward Objective-C headers or manual bridging. Your shared module becomes a first-class Swift Package Manager dependency.

kotlin
// shared/src/commonMain/kotlin/network/ApiClient.kt
expect class HttpClient {
    suspend fun get(url: String): Result<Response>
}

// shared/src/iosMain/kotlin/network/ApiClient.kt
actual class HttpClient private constructor(
    private val session: URLSession = .shared
) : HttpClient {
    actual suspend fun get(url: String): Result<Response> = 
        session.awaitData(URLRequest(url: URL(string: url)!))
            .map { Response(it) }
            .catch { Result.failure(it) }
}

// shared/src/androidMain/kotlin/network/ApiClient.kt
actual class HttpClient(
    private val client: OkHttpClient = OkHttpClient()
) : HttpClient {
    actual suspend fun get(url: String): Result<Response> =
        client.awaitResponse(Request.Builder().url(url).build())
            .map { Response(it.body?.string() ?: "") }
            .catch { Result.failure(it) }
}

Expect/Actual: The Contract That Works

The expect/actual mechanism forces platform boundaries into your architecture. You define interfaces in commonMain, implement them per platform. No leaky abstractions. No runtime surprises. The compiler enforces parity — if Android gets a new method, iOS won't compile until it's implemented.

"

Expect/actual isn't abstraction. It's a compile-time contract that prevents platform drift.

— Jake Wharton, Square

Ktor + Serialization = Shared Networking

Ktor 3.x with kotlinx.serialization handles your entire network stack in common code. JSON parsing, interceptors, auth tokens, retry logic — all shared. Platform-specific TLS pinning or certificate handling stays in actual implementations.

kotlin
// shared/src/commonMain/kotlin/network/Api.kt
@Serializable
data class User(
    @SerialName("id") val id: Long,
    @SerialName("name") val name: String,
    @SerialName("email") val email: String
)

interface UserApi {
    @GET("/users/{id}")
    suspend fun getUser(@Path("id") id: Long): User
}

// Usage in shared ViewModel
class UserViewModel(private val api: UserApi) : ViewModel() {
    private val _user = mutableStateOf<User?>(null)
    val user: State<User?> = _user

    fun loadUser(id: Long) = viewModelScope.launch {
        _user.value = api.getUser(id)
    }
}

Compose Multiplatform: Share UI Where It Makes Sense

Compose Multiplatform shares UI across Android, desktop, and web. For iOS, the 2026 consensus remains: native SwiftUI over a KMP shared layer. Platform fidelity matters for consumer apps. But internal tools, admin panels, and B2B apps? Compose on iOS via Kotlin/Native is viable and cuts UI code in half.

💡
TipUse Compose Multiplatform for shared design systems and internal tools. Keep consumer iOS UI in SwiftUI.

Build Pipeline Wins

KMP shifts complexity left. Your CI runs one test suite for shared logic. Android and iOS pipelines only test platform-specific code. Parallel builds become trivial — the shared module builds once, consumed as binary by both platforms.

MetricBefore KMPAfter KMP (2026)
Business logic lines~15k per platform~8k shared
Network layer bugsDuplicated fixesSingle fix
CI time (full)22 min14 min
Onboarding new devs2 weeks3 days

Migration Path for Existing Apps

Don't rewrite. Extract. Start with a single domain — analytics, auth, or networking. Move it to a KMP module. Publish as local Maven/XCFramework. Consume from both apps. Repeat. Each extraction reduces surface area for bugs.

⚠️
WarningAvoid sharing UI state holders (ViewModels) across platforms until your team is comfortable with the memory model differences between ART and ARC.

✦

Kotlin Multiplatform in 2026 isn't a bet. It's the default choice for new mobile products and a pragmatic extraction target for existing ones. The tooling caught up to the promise. Your duplicated business logic has no excuse left.

Share𝕏 Twitterin LinkedInin Whatsapp