In a Kotlin Multiplatform project, what is the `commonMain` source set and what kind of code belongs in it?
answer
- Root production source set, compiled per target
- Only stdlib + multiplatform-safe deps
- No java.*/android.*/platform.* directly
- expect/actual or interfaces for platform code
- src/commonMain/kotlin
basics
~10 scommonMain holds shared code that compiles to every target (JVM, iOS, JS, etc.). Put platform-independent logic there. It can only use APIs available on all targets.
solid answer
~40 s`commonMain` is the root production source set of a Kotlin Multiplatform module. Code placed there is compiled separately for every configured target, so it must only reference APIs and libraries available on all of them — the Kotlin standard library plus multiplatform-safe dependencies. You write shared business logic, data models, networking/serialization wiring, and `expect` declarations here. Platform-specific pieces live in target source sets like `jvmMain` or `iosMain` (often as `actual` implementations). Because `commonMain` cannot see `java.*`, `android.*`, or `platform.Foundation.*`, anything platform-bound must be abstracted behind an interface or an `expect`/`actual` pair. It is configured in `build.gradle.kts` via the `kotlin { sourceSets { commonMain { ... } } }` block.
code
kotlin · 6 lines// src/commonMain/kotlin/Greeting.kt
expect fun platformName(): String
class Greeting {
fun greet(): String = "Hello from ${platformName()}"
}go deeper
Knows commonMain holds shared code and only multiplatform APIs are allowed.
Explains compilation per target and the expect/actual escape hatch with correct directory layout.
Discusses dependency safety (artifacts must exist for every target) and abstraction strategies for platform code.
Frames common-code design as an architecture decision: maximizing shared surface while isolating platform concerns behind stable interfaces.
## What `commonMain` is A Kotlin Multiplatform (KMP) module organizes code into **source sets**. `commonMain` is the root *production* source set: every Kotlin file under `src/commonMain/kotlin` is compiled **once per target** that the module declares (e.g. `jvm()`, `iosArm64()`, `js()`, `linuxX64()`). The same source therefore produces a JVM `.class`, an iOS Kotlin/Native binary, a JS module, and so on. ## The hard constraint: lowest common denominator Because that one file must compile for *all* targets, `commonMain` may only reference: - The **Kotlin standard library** (`kotlin.*`, `kotlin.collections.*`, `kotlin.time.*`, `kotlin.coroutines` if added, etc.) — these are multiplatform. - **Multiplatform-safe libraries** — ones that publish artifacts for every target you use (kotlinx.coroutines, kotlinx.serialization, Ktor client, etc.). It **cannot** reference platform-only APIs: no `java.io.File`, no `android.content.Context`, no `platform.UIKit.*`. Those only exist in their respective target source sets. ## Where platform-specific code goes Two escape hatches let common code reach platform APIs: - **Interfaces / abstractions** — declare an interface in `commonMain`, implement it per platform. - **`expect`/`actual`** — declare `expect fun currentTimeMillis(): Long` in `commonMain`; provide an `actual` in each target source set. ```kotlin // src/commonMain/kotlin/Platform.kt expect fun platformName(): String class Greeting { fun greet(): String = "Hello, ${platformName()}!" } ``` ```kotlin // src/jvmMain/kotlin/Platform.kt actual fun platformName(): String = "JVM ${System.getProperty("java.version")}" ``` ## Gradle configuration `commonMain` and its dependencies are declared in the `kotlin {}` DSL: ```kotlin kotlin { jvm() iosArm64() sourceSets { commonMain.dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") } } } ``` ## Key takeaways - `commonMain` = shared, compiled-to-every-target code. - Only stdlib + multiplatform-safe deps allowed. - Reach platform APIs via interfaces or `expect`/`actual`, never directly.
- Why can't you use `java.io.File` directly in `commonMain`?`java.io.File` is part of the JVM/Android platform only; iOS, JS, and Native targets have no JVM, so the code wouldn't compile for them. Common code is limited to APIs present on every target.
- How does common code call platform-specific functionality?Via an `expect` declaration with per-target `actual` implementations, or by declaring an interface in common and injecting a platform implementation.
commonMain is like writing in a language every team member speaks — you can only use words (APIs) everyone understands; specialized jargon goes in per-team handbooks (target source sets).
saying these in an interview costs you the question
- Thinking `commonMain` can use Java standard library classes
- Believing common code is compiled only once for all targets
- Confusing `commonMain` with a separate compiled JAR shared at runtime
- Not knowing about `expect`/`actual` as the escape hatch
- Claiming any Maven dependency can be added to `commonMain`