skip to content

What is the difference between jvmToolchain(...) and compilerOptions.jvmTarget, and how do they interact?

level: middleimportance: must knowfreq 55%

answer

  1. toolchain = which JDK; jvmTarget = bytecode level
  2. jvmTarget <= toolchain version
  3. JvmTarget enum: JVM_1_8 / JVM_11 / JVM_17 / JVM_21
  4. toolchain enables Gradle auto-download + reproducibility
  5. align Kotlin jvmTarget with Java release to avoid mismatch error

basics

~10 s

jvmToolchain 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 lines
kotlin
kotlin {
    jvmToolchain {
        languageVersion.set(JavaLanguageVersion.of(21))
    }
    jvm {
        compilerOptions {
            jvmTarget.set(JvmTarget.JVM_17)
        }
    }
}

go deeper

for a junior

Recognizes both exist and that one is the JDK and one is the bytecode version.

for a middle

Clearly separates toolchain (which JDK) from jvmTarget (bytecode level) and states the <= constraint.

for a senior

Explains reproducibility, auto-provisioning, and aligning Kotlin/Java levels to avoid mismatch errors.

for a principal

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

context