What is the difference between jvmToolchain(...) and compilerOptions.jvmTarget, and how do they interact?
answer
- toolchain = which JDK; jvmTarget = bytecode level
- jvmTarget <= toolchain version
- JvmTarget enum: JVM_1_8 / JVM_11 / JVM_17 / JVM_21
- toolchain enables Gradle auto-download + reproducibility
- align Kotlin jvmTarget with Java release to avoid mismatch error
basics
~10 sjvmToolchain picks which JDK version actually compiles and runs your code. jvmTarget sets the bytecode version the compiler emits. The toolchain is the tool; jvmTarget is the output format.
solid answer
~40 s`jvmToolchain(N)` uses Gradle's Java toolchain support to select a specific JDK (version N) to compile and run with, independent of the JDK that launched Gradle — Gradle can auto-download it. Setting the toolchain also makes that JDK's release the default **bytecode level**, so both Kotlin and Java compile to that version. `compilerOptions.jvmTarget` (an enum like `JvmTarget.JVM_17`) explicitly sets the **bytecode version** the Kotlin compiler emits, regardless of the JDK version. The key rule: `jvmTarget` must be **less than or equal to** the toolchain JDK's version — you can compile to JVM 11 bytecode using a JDK 21 toolchain, but not to JVM 21 bytecode with a JDK 17 toolchain. In KMP you set these inside `jvm { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) } }` and `kotlin { jvmToolchain(21) }`.
code
kotlin · 10 lineskotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
jvm {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
}go deeper
Recognizes both exist and that one is the JDK and one is the bytecode version.
Clearly separates toolchain (which JDK) from jvmTarget (bytecode level) and states the <= constraint.
Explains reproducibility, auto-provisioning, and aligning Kotlin/Java levels to avoid mismatch errors.
Sets org-wide conventions for deployment floor vs build JDK and reasons about migration when bumping the production JVM.
## Two distinct knobs People conflate these, but they answer different questions: - **`jvmToolchain(N)`** — *Which JDK compiles and runs my code?* It uses **Gradle's Java Toolchain** feature to pick (and optionally auto-provision/download) a JDK of major version N. This decouples your build from whatever JDK happens to launch Gradle, making builds reproducible across machines. - **`compilerOptions.jvmTarget`** — *What bytecode version does the compiler emit?* It is a `JvmTarget` enum (`JVM_1_8`, `JVM_11`, `JVM_17`, `JVM_21`, …) that controls the **class-file major version**, i.e. the minimum JVM that can load the output. ## How they interact When you set a toolchain, Kotlin and Java both default their bytecode level to that JDK's release. If you set `jvmTarget` separately, it **overrides** the bytecode level but **not** which JDK runs. The hard constraint: a JDK can only emit bytecode **at or below** its own version. So: - Toolchain 21 + jvmTarget JVM_17 -> valid (compile down to 17 using a newer JDK). - Toolchain 17 + jvmTarget JVM_21 -> **error** (can't emit 21 bytecode on JDK 17). ```kotlin kotlin { jvmToolchain(21) // compile & run with JDK 21 (auto-downloadable) jvm { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) // but emit JVM 17 bytecode } } } ``` ## Why keep them separate - **Deployment floor**: your code must run on JVM 17 in production -> `jvmTarget = JVM_17`, even though developers build with JDK 21. - **Reproducibility**: pinning the toolchain means everyone compiles with the same JDK regardless of their local install. - **Java/Kotlin alignment**: in mixed projects, set both Kotlin's `jvmTarget` and Java's `release`/`targetCompatibility` to the same level so the combined classpath is consistent. A mismatch can cause `Inconsistent JVM-target compatibility` errors. ## Default behavior If you set neither, Kotlin targets a default (currently `JVM_1_8` historically, but modern Kotlin/Gradle plugins align with the toolchain). Always set them explicitly for clarity.
- Can you set jvmTarget higher than the toolchain JDK version?No. A JDK can only emit bytecode at or below its own major version, so the build fails if jvmTarget exceeds the toolchain.
- Why might you compile to JVM_17 bytecode while using a JDK 21 toolchain?Production runs on JVM 17, so the output must load there, but developers benefit from the newer JDK 21 toolchain for compilation/tests.
The toolchain is the factory machine doing the work; jvmTarget is the format spec the parts must match for the destination assembly line.
saying these in an interview costs you the question
- Claiming jvmTarget chooses which JDK runs the build
- Saying you can target JVM 21 bytecode with a JDK 17 toolchain
- Not knowing jvmTarget is a JvmTarget enum, not a raw string in modern config
- Ignoring the need to align Kotlin and Java bytecode levels in mixed modules