skip to content

How do you tell an Android Gradle Plugin (AGP) project which JDK to use to compile Java and Kotlin, using a JVM toolchain?

level: juniorimportance: must knowfreq 55%

answer

  1. jvmToolchain(17)
  2. decouples Gradle JDK from compile JDK
  3. java { toolchain { languageVersion } }
  4. AGP applies to JavaCompile
  5. reproducible builds

basics

~10 s

Set a JVM toolchain language version. With the Kotlin plugin use kotlin { jvmToolchain(17) }; AGP picks up that JDK to compile Java and Kotlin instead of the JDK running Gradle.

solid answer

~30 s

A JVM toolchain decouples the JDK that *runs* Gradle from the JDK that *compiles* your code. In an AGP project the simplest declaration is `kotlin { jvmToolchain(17) }` (Kotlin Gradle Plugin), which Gradle resolves to a real JDK 17 install (auto-provisioning it if a resolver is configured). The Kotlin plugin propagates that toolchain to Kotlin compilation, and AGP aligns Java compilation and `compileOptions` source/target to it. You can also configure `java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }` directly. The benefit: the build is reproducible and independent of whatever JDK the developer or CI machine happens to launch Gradle with.

code

kotlin · 11 lines
kotlin
// app/build.gradle.kts
kotlin {
    jvmToolchain(17)
}

// equivalent low-level form:
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

go deeper

for a junior

Know the one-liner kotlin { jvmToolchain(17) } and that it picks the JDK used to compile.

for a middle

Explain the Gradle-JDK vs toolchain-JDK distinction and that the Kotlin plugin propagates the toolchain to both Java and Kotlin.

for a senior

Discuss reproducibility, auto-provisioning fallback, and how AGP's JavaCompile inherits the toolchain language version.

for a principal

Standardize toolchain language versions across an Android monorepo so every module and CI agent compiles identically regardless of the launching JDK.

## What a JVM toolchain is Gradle separates two JDKs: - the **Gradle JDK** — the JVM that launches and runs the Gradle daemon; - the **toolchain JDK** — the JVM used to *compile* and (optionally) test your code. A **JVM toolchain** lets you declare the second one by *language version* (`17`, `21`, …) rather than hard-coding a path. Gradle then locates a matching JDK on the machine (or downloads one if auto-provisioning is enabled). This makes the build reproducible regardless of which JDK started Gradle. ## Declaring it in an AGP build There are two common entry points: 1. **Via the Kotlin Gradle Plugin** (recommended in Android, since most modules are Kotlin): `kotlin { jvmToolchain(17) }`. This is sugar over the Java toolchain — it sets the same `JavaLanguageVersion` and wires it into Kotlin compilation. 2. **Via the `java` extension directly:** `java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }`. ## How AGP consumes it AGP reads the project's Java toolchain and applies its language version to `JavaCompile` tasks. When the Kotlin plugin and AGP agree on the same toolchain, both Java and Kotlin compile against JDK 17, and `compileOptions.sourceCompatibility/targetCompatibility` default to the toolchain language version unless overridden. ## Why prefer a toolchain over `JAVA_HOME` - Reproducible: CI and laptops compile with the same JDK. - The Gradle daemon can keep running on a newer JDK (e.g. 21) while still producing JDK-17 bytecode. - It plays with Foojay auto-provisioning so missing JDKs download automatically. ```kotlin // app/build.gradle.kts plugins { id("com.android.application") id("org.jetbrains.kotlin.android") } android { compileSdk = 34 // compileOptions left to inherit the toolchain language version } kotlin { jvmToolchain(17) // one line: Java + Kotlin compile on JDK 17 } ```

  • Does `jvmToolchain(17)` configure both Java and Kotlin compilation?
    Yes. The Kotlin plugin sets the Java toolchain language version and wires Kotlin compilation to the same JDK, so both `JavaCompile` and Kotlin compile tasks run on JDK 17.
  • What happens if no JDK 17 is installed locally?
    Gradle fails to resolve the toolchain unless auto-provisioning (e.g. the Foojay resolver plugin) is configured, in which case it downloads a matching JDK.

The Gradle JDK is the kitchen you cook in; the toolchain JDK is the recipe's required oven temperature — you fix the temperature so the dish comes out the same no matter whose kitchen runs it.

saying these in an interview costs you the question

  • Claiming the toolchain changes which JDK runs the Gradle daemon — it only changes the compile JDK.
  • Confusing toolchain *language version* with `compileSdk`/`targetSdk` (Android API levels).

context