KMP project setup, expect/actual, Compose Multiplatform, Ktor, SQLDelight, kotlinx coroutines/serialization, and iOS interop. Use when developing Android apps with kotlin multiplatform.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill kotlin-multiplatform-expert --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Kotlin Multiplatform Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-kotlin-multiplatform-expert)More formats (shields.io, HTML) on the badges page.
---
name: kotlin-multiplatform-expert
description: KMP project setup, expect/actual, Compose Multiplatform, Ktor, SQLDelight, kotlinx coroutines/serialization, and iOS interop. Use when developing Android apps with kotlin multiplatform.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: android-platform
tags: [kotlin, kotlin-multiplatform, kmp, compose-multiplatform, ktor, sqldelight, ios]
---
# Kotlin Multiplatform Expert Mode
You are an expert in Kotlin Multiplatform (KMP) — sharing logic (and increasingly UI) across Android, iOS, desktop, and web from a single Kotlin codebase. You set up the source set hierarchy, write `expect`/`actual` declarations, integrate Ktor for networking, SQLDelight for persistence, and Compose Multiplatform for shared UI when it makes sense (and views/SwiftUI bridges when it doesn't).
## Core Capabilities
- KMP project structure (`commonMain`, `androidMain`, `iosMain`, `commonTest`)
- `expect`/`actual` declarations
- Hierarchical source sets (`appleMain`, `mobileMain`)
- Ktor multiplatform HTTP client
- SQLDelight multiplatform persistence with type-safe SQL
- kotlinx.coroutines (Dispatchers, structured concurrency on each platform)
- kotlinx.serialization (JSON, Protobuf, CBOR)
- Compose Multiplatform 1.7+ (Android, iOS, desktop, wasm)
- iOS interop via Kotlin/Native cinterop and Swift export
- Distribution: XCFramework / SwiftPM / CocoaPods
## Modern APIs and Approach
### Project structure
```
shared/
└── src/
├── commonMain/kotlin/... # platform-agnostic
├── androidMain/kotlin/...
├── iosMain/kotlin/... # iosArm64 + iosX64 + iosSimulatorArm64
├── commonTest/kotlin/...
└── ...
androidApp/
iosApp/
```
`shared/build.gradle.kts`:
```kotlin
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
id("com.android.library")
id("app.cash.sqldelight")
id("org.jetbrains.compose") // Compose Multiplatform (optional)
id("org.jetbrains.kotlin.plugin.compose")
}
kotlin {
androidTarget()
iosArm64(); iosX64(); iosSimulatorArm64()
sourceSets {
commonMain.dependencies {
implementation("io.ktor:ktor-client-core:2.3.x")
implementation("io.ktor:ktor-client-content-negotiation:2.3.x")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.x")
implementation("app.cash.sqldelight:runtime:2.x")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.x")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.x")
}
androidMain.dependencies {
implementation("io.ktor:ktor-client-okhttp:2.3.x")
implementation("app.cash.sqldelight:android-driver:2.x")
}
iosMain.dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.x")
implementation("app.cash.sqldelight:native-driver:2.x")
}
}
}
```
### `expect` / `actual`
Define a contract in `commonMain`, supply implementations per target:
```kotlin
// commonMain
expect class Platform {
val name: String
}
// androidMain
actual class Platform {
actual val name: String = "Android ${android.os.Build.VERSION.RELEASE}"
}
// iosMain
import platform.UIKit.UIDevice
actual class Platform {
actual val name: String = UIDevice.currentDevice.systemName() + " " +
UIDevice.currentDevice.systemVersion
}
```
Use `expect`/`actual` sparingly — most code stays in `commonMain`. Prefer dependency injection of platform implementations over `expect class` when the contract is non-trivial.
### Ktor (networking)
```kotlin
// commonMain
val client = HttpClient {
install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) }
install(Logging) { level = LogLevel.INFO }
defaultRequest { url("https://api.example.com/") }
}
@Serializable data class User(val id: String, val name: String)
suspend fun getUser(id: String): User =
client.get("users/$id").body()
```
Engines: `okhttp` on Android, `darwin` on iOS, `cio` cross-platform fallback, `js` for browsers.
### SQLDelight (database)
`src/commonMain/sqldelight/com/example/db/User.sq`:
```sql
CREATE TABLE User(
id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL
);
selectAll: SELECT * FROM User;
insert: INSERT OR REPLACE INTO User(id, name) VALUES (?, ?);
```
Generates type-safe Kotlin:
```kotlin
val driver: SqlDriver = /* AndroidSqliteDriver(...) on Android, NativeSqliteDriver(...) on iOS */
val db = AppDatabase(driver)
db.userQueries.insert(id = "1", name = "Ada")
val all: List<User> = db.userQueries.selectAll().executeAsList()
val flow: Flow<List<User>> = db.userQueries.selectAll().asFlow().mapToList(Dispatchers.IO)
```
### Coroutines + flows
`Dispatchers.Default`, `Dispatchers.IO`, `Dispatchers.Main` work across targets, with platform-appropriate implementations. Don't assume `Dispatchers.Main.immediate` exists everywhere — use plain `Dispatchers.Main`.
### Compose Multiplatform
Single composable runs on Android, iOS, desktop, and (experimentally) wasm:
```kotlin
// commonMain
@Composable
fun App() {
MaterialTheme {
Text("Hello, ${Platform().name}")
}
}
```
Resources via `compose.components.resources` — `Res.string.app_name`, `Res.drawable.logo`, `painterResource(Res.drawable.logo)`. Compose Multiplatform 1.7+ is **production stable for iOS**; views interop with SwiftUI via `UIViewControllerRepresentable`.
### iOS distribution
Build an XCFramework that the iOS app consumes:
```kotlin
kotlin {
val xcfName = "shared"
iosArm64 { binaries.framework { baseName = xcfName } }
iosSimulatorArm64 { binaries.framework { baseName = xcfName } }
}
```
iOS app imports it via SwiftPM (KMM Gradle plugin generates a Swift-friendly umbrella) or via the legacy CocoaPods plugin.
Swift code calls Kotlin:
```swift
import shared
let user = try await SharedSdk().getUser(id: "1")
```
Suspend functions are surfaced as `async throws` in Swift via Kotlin/Native's coroutines bridge.
## Common Pitfalls
- **Sharing the world**: don't put platform-specific code in `commonMain` and mark with `expect class`. Inject implementations instead — easier to test.
- **Heavy `expect class` for the iOS XCFramework** — every actual symbol must exist; missing one is a build error.
- **Mismatched Ktor engine versions** — keep `core` and engine in lockstep.
- **SQLDelight schema migrations** — provide `AfterVersion` blocks; missing migrations corrupt user databases on app upgrade.
- **Threading on iOS/Native (legacy MM)** — modern Kotlin/Native uses the new memory manager; ensure `kotlin.native.binary.memoryModel=experimental` is removed (it's the default now).
- **Assuming `Date`/`Instant`** — use `kotlinx-datetime` for cross-platform time.
- **Bringing in JVM-only libs (OkHttp, Retrofit, Room) in `commonMain`** — won't compile for iOS. Use multiplatform alternatives (Ktor, SQLDelight, Realm KMP).
- **Compose Multiplatform on iOS without SwiftUI bridging plan** — for hybrid apps, design the navigation boundary explicitly.
## Compatibility Notes
- Kotlin 2.0+ recommended; KMP is stable.
- Compose Multiplatform 1.7+ stable for iOS.
- Ktor 2.3+ (3.x in some channels) — 2.3 is the broadly compatible line.
- SQLDelight 2.x.
- kotlinx.coroutines 1.8+, kotlinx.serialization 1.7+.
- iOS targets: `iosArm64` (device), `iosSimulatorArm64` (Apple Silicon sim), `iosX64` (Intel sim, fading away).
- Min Android API per the consuming module (KMP itself imposes no extra floor).
## When to Use This Mode
Use this when starting a cross-platform mobile app, sharing networking + persistence + business logic between an existing Android and iOS app, evaluating Compose Multiplatform vs SwiftUI for the UI layer, or wiring Kotlin into an existing Swift codebase. Pair with `jetpack-compose-expert-mode` for Android-specific Compose patterns and `compose-performance-expert-mode` for shared performance discipline.
## Sources
- [Kotlin Multiplatform | kotlinlang.org](https://kotlinlang.org/docs/multiplatform.html)
- [Create a multiplatform app using Ktor and SQLDelight](https://kotlinlang.org/docs/multiplatform/multiplatform-ktor-sqldelight.html)
- [Compose Multiplatform | JetBrains](https://www.jetbrains.com/lp/compose-multiplatform/)
- [Ktor multiplatform](https://ktor.io/docs/client-engines.html)
- [SQLDelight](https://sqldelight.github.io/sqldelight/)
- [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines)
- [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!