Kotlin Multiplatform Multi Module structure
Introduction
A quick Compose/Kotlin multiplatform multi module architecture approach to make code comprehension clean.
Key Points
- Kotlin Modules vs Kotlin Multiplatform Modules
- Multi Module Graph
Section 1: Kotlin Modules vs Kotlin Multiplatform Modules
-
A normal Kotlin module (JVM/Android) targets one runtime one main source set
- JVM(
kotlin(""jvm)) - src/main/kotlin - Android(
kotlin("android")) - src/main/kotlin - All the code is compiled for one platform.
- JVM(
-
Kotlin Multiplatform (KMP / KMM) module
- A Kotlin Multiplatform module is multi-target by design.
- Instead of “one module = one platform”, it’s:
- one module → multiple targets → multiple source sets
-
The key difference is the
- source set hierarchy
src/
commonMain/
commonTest/
androidMain/
androidTest/
iosMain/
iosTest/
- Gradle configuration and compilation model
plugins {
kotlin("multiplatform")
}
kotlin {
androidTarget()
iosX64()
iosArm64()
sourceSets {
val commonMain by getting
val androidMain by getting
val iosMain by getting
}
}-
commonMain
→ pure Kotlin (no Android / iOS APIs) -
androidMain
→ Android-specific implementations -
iosMain
→ iOS-specific implementations -
commonMainis compiled once -
Platform source sets are compiled per target
-
Gradle enforces platform boundaries
-
expect / actualand dependency isolation are enabled
Section 2: Multi Module Approach
-
Instead of separating the whole system into
coredomaindatepresentation
-
We want an approach that mixes those into a more organized multi module approach.
core- Contains logic that is shared across multiple features and is safe for reuse.
- It is still layered internally to preserve separation of concerns:
core:presentation- Shared UI primitives
- Navigation helpers
- State holders / base ViewModels
core:domain- Shared models
- Common use cases
- Error types
core:data- Shared repositories or data abstractions
- Network helpers
core:designsystem- Reusable Compose components
- Theme, typography, spacing
- Custom design library (UI contract, not screens)
featurejog- applying those buckets on the feature level, allowing for code cleanliness and isolationdomaindatadatabasepresentation
settingsdomainpresentation
Conclusion
This approach reduces overall module size while increasing clarity, cohesion, and isolation.
By slicing the system vertically by feature and keeping core focused on true shared infrastructure, we create an architecture that is:
- Easier to reason about
- Safer to change
- More scalable as the codebase grows