Skip to content
Back to skills

Kotlin Multiplatform Expert

ASecurity

KMP project setup, expect/actual, Compose Multiplatform, Ktor, SQLDelight, kotlinx coroutines/serialization, and iOS interop. Use when developing Android apps with kotlin multiplatform.

  • 9 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 8, 2026
developmentgoswiftkotlinsqlgitapidatabaseperformance

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add anubhavg-icpl/vibe --skill kotlin-multiplatform-expert --agent claude-code

Installs 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 with every re-scan.

Security grade badge for Kotlin Multiplatform Expert
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anubhavg-icpl-kotlin-multiplatform-expert/badge)](https://www.skillsdirectory.com/skills/anubhavg-icpl-kotlin-multiplatform-expert)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.