What do compilerOptions { languageVersion } and apiVersion mean in the Kotlin Gradle Plugin, and when would you set them?
answer
- languageVersion = source syntax/feature level
- apiVersion = stdlib API you may call
- apiVersion <= languageVersion
- both default to the compiler version
- used for migration / library compat
basics
~20 slanguageVersion tells the Kotlin compiler which version of the Kotlin language/syntax to accept; apiVersion restricts which stdlib/runtime API you may use to that version. You set them to compile in a compatibility mode older than the compiler you're running.
solid answer
~40 sBoth are compiler options under `kotlin { compilerOptions { … } }`, set with the `KotlinVersion` enum. `languageVersion` controls the source language level — the syntax and language features the compiler accepts and the semantics it applies; e.g. running a 2.0 compiler but with `languageVersion = KOTLIN_1_9` to ease a gradual migration. `apiVersion` caps the Kotlin **library API** you are allowed to call, so you don't accidentally use stdlib declarations newer than your minimum supported Kotlin runtime; it must be ≤ `languageVersion`. Typical reasons: library authors who must stay compatible with consumers on older Kotlin, or teams migrating across a major compiler bump in controlled steps. If unset, both default to the compiler's own version. They are independent of `jvmTarget`, which is about emitted JVM bytecode, not Kotlin language level.
code
kotlin · 10 linesimport org.jetbrains.kotlin.gradle.dsl.KotlinVersion
kotlin {
compilerOptions {
// Run a newer compiler but keep older language semantics during migration
languageVersion.set(KotlinVersion.KOTLIN_1_9)
// Don't call stdlib APIs newer than what consumers ship
apiVersion.set(KotlinVersion.KOTLIN_1_9)
}
}go deeper
Recognize these exist and default to the compiler version; not expected to configure them.
Distinguish languageVersion (syntax/features) from apiVersion (stdlib API) and give the migration use case.
Explain library-compatibility motivations, the apiVersion ≤ languageVersion rule, and that both are independent of jvmTarget.
Set org-wide policy: pin during major Kotlin migrations (e.g. K2) and define how library modules choose apiVersion for downstream consumers.
## Three independent version axes KGP exposes three things that all sound like "version" but mean different things: - **jvmTarget** — the JVM bytecode the compiler emits. - **languageVersion** — which Kotlin *language* the compiler reads (syntax + feature set + semantics). - **apiVersion** — which Kotlin *standard-library/runtime API* your code is permitted to reference. This question is about the latter two. ## languageVersion The Kotlin compiler can operate in a backward-compatibility mode: a newer compiler can be told to behave as if it were an older language version. You configure it as: ```kotlin import org.jetbrains.kotlin.gradle.dsl.KotlinVersion kotlin { compilerOptions { languageVersion.set(KotlinVersion.KOTLIN_1_9) } } ``` With this, code using features introduced after 1.9 will be rejected, and the compiler applies 1.9 semantics. The classic use case is a **gradual migration** across a major bump (e.g. the K2 / 2.0 change): you upgrade the compiler but pin `languageVersion` to the previous level so the codebase keeps building unchanged, then lift the pin later. ## apiVersion `apiVersion` restricts which declarations from the Kotlin stdlib and runtime you may call to those available in that version: ```kotlin kotlin { compilerOptions { apiVersion.set(KotlinVersion.KOTLIN_1_8) } } ``` If you call a stdlib function introduced in 1.9 while `apiVersion` is 1.8, the compiler errors. **Library authors** use this so a library compiled with a new toolchain still runs against the older Kotlin runtime their consumers ship. The constraint `apiVersion ≤ languageVersion` must hold. ## Defaults and relationships If you set neither, both equal the compiler's bundled version (so a Kotlin 2.0 compiler defaults both to 2.0). They have nothing to do with `jvmTarget`: you can target JVM_17 bytecode while using `languageVersion = 1.9`. Don't reach for these knobs casually — most application builds should track the compiler version and only pin during a deliberate migration or for library compatibility.
- Why must apiVersion be less than or equal to languageVersion?You can't reference a library API from a Kotlin version newer than the language level you're compiling against — the compiler enforces apiVersion ≤ languageVersion to keep that coherent.
- Do these affect emitted bytecode version?No. languageVersion/apiVersion are Kotlin-level concerns; jvmTarget is the independent knob for JVM bytecode. You can mix, e.g. languageVersion 1.9 with jvmTarget JVM_21.
saying these in an interview costs you the question
- Confusing languageVersion with jvmTarget (Kotlin language level vs JVM bytecode).
- Saying apiVersion can exceed languageVersion — the compiler rejects that.