← All courses

Project Structure & Source Sets

🗓 May 31, 2026 ⏱ 2 min read

The shape of a KMP project

A typical KMP project has a shared module plus the platform apps. The shared module is where the magic happens; the Android and iOS apps consume it.

project/
├── androidApp/        # the Android app (Jetpack Compose, etc.)
├── iosApp/            # the iOS app (SwiftUI, Xcode project)
└── shared/            # the Kotlin Multiplatform module
    └── src/
        ├── commonMain/   # shared Kotlin for ALL platforms
        ├── androidMain/  # Android-only Kotlin
        └── iosMain/      # iOS-only Kotlin

Source sets explained

  • commonMain — code that works on every target. Put as much here as possible: models, networking, business logic.
  • androidMain — code that can use Android APIs (e.g. Context).
  • iosMain — code that can call Apple/iOS APIs.
  • commonTest / androidTest / iosTest — tests, mirroring the same split.

Code in commonMain can only use multiplatform libraries — it can’t reference Android or iOS APIs directly (that’s what the platform source sets are for).

Configuring targets in Gradle

The shared module’s build.gradle.kts declares which platforms you target and which libraries each source set uses.

kotlin {
    androidTarget()
    iosArm64()             // real iPhones
    iosSimulatorArm64()    // the simulator on Apple silicon

    sourceSets {
        commonMain.dependencies {
            implementation("io.ktor:ktor-client-core:2.3.12")
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
        }
        androidMain.dependencies {
            implementation("io.ktor:ktor-client-okhttp:2.3.12")
        }
        iosMain.dependencies {
            implementation("io.ktor:ktor-client-darwin:2.3.12")
        }
    }
}

Notice the same Ktor client is in common, but each platform adds its own engine (OkHttp on Android, Darwin on iOS) — a very common KMP pattern.

How each app uses the shared module

  • Android — adds shared as a normal Gradle dependency and calls its classes directly.
  • iOS — Gradle builds the shared module into a native framework that the Xcode project imports; Swift then calls it like any library.

Getting started quickly

Use the official Kotlin Multiplatform wizard (or the Android Studio KMP plugin) to generate this whole structure for you, pre-configured — far easier than setting it up by hand.

Common mistakes

  • Trying to use an Android API in commonMain (it won’t compile for iOS).
  • Forgetting to add a platform-specific engine/dependency (e.g. the Ktor Darwin engine for iOS).
  • Setting up the project by hand instead of using the wizard.
Summary: A KMP project has a shared module with commonMain (works everywhere) plus androidMain/iosMain for platform code. Configure targets and per-platform dependencies in Gradle, and let each app consume the shared module natively.