skip to content

Multiplatform Gradle Setup

The multiplatform plugin is where you declare targets, wire the source-set hierarchy, and attach dependencies per platform. Most KMP problems are really configuration problems in this block.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

In a Kotlin Multiplatform build, how do you apply the plugin and declare which platforms (targets) your library should compile for?

level: juniorimportance: must knowfreq 70%

answer

  1. plugins { kotlin("multiplatform") }
  2. kotlin { } extension block
  3. jvm() / js(IR) / native targets
  4. each target -> XMain / XTest source sets
  5. name JVM variants: jvm("desktop")

basics

~10 s

Apply the kotlin("multiplatform") plugin, then inside the kotlin { } block call functions like jvm(), js(), and a native target such as linuxX64(). Each call adds a platform you compile for.

solid answer

~30 s

In build.gradle.kts you apply the plugin with `kotlin("multiplatform")` in the plugins { } block. Inside the `kotlin { }` extension you declare targets by calling functions: `jvm()` for the JVM, `js(IR) { browser(); nodejs() }` for JavaScript, and native targets like `linuxX64()`, `macosArm64()`, `iosArm64()`. Each target function registers compilations and creates source sets (e.g. jvmMain, jsMain). Some helpers expand to several targets — `iosArm64() + iosSimulatorArm64()` cover device and simulator; the convenience `iosX64/iosArm64` are declared individually. You can name targets, e.g. `jvm("desktop")`, when you need two JVM variants. The set of declared targets defines exactly which platform artifacts Gradle produces.

code

kotlin · 13 lines
kotlin
plugins {
    kotlin("multiplatform") version "2.1.0"
}

kotlin {
    jvm()
    js(IR) {
        browser()
        nodejs()
    }
    iosArm64()
    iosSimulatorArm64()
}

go deeper

for a junior

Can apply kotlin("multiplatform") and call jvm()/js() to declare targets, and knows source sets appear per target.

for a middle

Explains native targets, js(IR) environments, and naming a JVM target to create variants.

for a senior

Reasons about the target set as a shipping contract and how adding a target forces new actual implementations.

for a principal

Weighs target matrix breadth vs. CI cost and the API-surface commitment of supporting each platform long-term.

## What a "target" is A **target** in Kotlin Multiplatform (KMP) is one platform you compile your code for — the JVM, JavaScript, or a Kotlin/Native platform (iOS, Linux, macOS, Windows, etc.). Declaring a target tells the Kotlin Gradle plugin to set up compilations, source sets, and produce an artifact for that platform. ## Applying the plugin KMP is driven by the `org.jetbrains.kotlin.multiplatform` Gradle plugin. In the Kotlin DSL you usually write the accessor form: ```kotlin plugins { kotlin("multiplatform") version "2.1.0" } ``` Applying it adds the `kotlin { }` extension block where all multiplatform configuration lives. ## Declaring targets Inside `kotlin { }` you call a function per platform: ```kotlin kotlin { jvm() // JVM target -> jvmMain / jvmTest js(IR) { // JavaScript (IR backend) browser() nodejs() } linuxX64() // Kotlin/Native Linux macosArm64() // Kotlin/Native macOS Apple Silicon iosArm64() // iOS device iosSimulatorArm64() // iOS simulator on Apple Silicon } ``` - `jvm()` — compiles to JVM bytecode. You can pass a **name** like `jvm("desktop")` to declare more than one JVM variant. - `js(IR)` — JavaScript via the **IR** compiler backend (the legacy backend is removed in current Kotlin). The `browser()` / `nodejs()` sub-blocks pick the run/test environment. - **Native targets** (`linuxX64`, `mingwX64`, `macosArm64`, `iosArm64`, …) compile through Kotlin/Native to native binaries via LLVM. ## What each target call creates For a target `X`, the plugin creates a default `main` and `test` compilation, and corresponding source sets named `XMain` and `XTest` (for `jvm()` that's `jvmMain`/`jvmTest`). These are wired beneath the shared `commonMain`/`commonTest` source sets. ## Why it matters The set of declared targets is the contract for which platforms your library ships. Adding `iosArm64()` later, for example, forces you to provide `actual` implementations for any `expect` declarations on that platform.

  • What happens to source sets when you call jvm()?
    It creates jvmMain and jvmTest source sets (plus the jvm compilations), automatically depending on commonMain/commonTest.
  • Why might you write jvm("desktop")?
    To declare two distinct JVM targets in the same module; the name disambiguates their source sets (desktopMain) and configurations.

Declaring targets is like choosing which countries to print a passport edition for — each one you add means a separate, valid document you must produce.

saying these in an interview costs you the question

  • Thinking targets are applied with separate plugins instead of function calls in kotlin { }
  • Using the removed legacy JS backend instead of js(IR)
  • Believing one jvm() call can produce iOS or JS output
  • Not knowing each target generates its own source sets

context

open as a page

Explain commonMain and commonTest source sets in KMP and how platform source sets relate to them.

level: middleimportance: must knowfreq 65%

basics

~10 s

commonMain holds code shared by every target; commonTest holds shared tests. Platform source sets like jvmMain depend on commonMain, so they see common code and add platform-specific code on top.

open as a page

How does expect/actual work in a KMP module, and where do you place each declaration across source sets?

level: middleimportance: must knowfreq 60%

basics

~20 s

You write an expect declaration in commonMain describing an API with no body, then provide a matching actual implementation in each platform source set. The compiler links them so common code can call the platform-specific implementation.

open as a page

How do you declare dependencies in a KMP module so common code and individual platforms each get the right libraries?

level: seniorimportance: should knowfreq 50%

basics

~10 s

Add shared libraries inside commonMain's dependencies block (they must be multiplatform), and add platform-only libraries inside that platform's source-set dependencies block, like jvmMain or androidMain.

open as a page

What is the KMP default hierarchy template, and when would you customize intermediate source sets with applyDefaultHierarchyTemplate or manual dependsOn?

level: seniorimportance: nice to knowfreq 35%

basics

~10 s

The default hierarchy template auto-creates intermediate source sets (like nativeMain, appleMain, iosMain) that group related targets so you can share code among a subset of platforms without wiring them by hand.

open as a page