How do you tell an Android Gradle Plugin (AGP) project which JDK to use to compile Java and Kotlin, using a JVM toolchain?
answer
- jvmToolchain(17)
- decouples Gradle JDK from compile JDK
- java { toolchain { languageVersion } }
- AGP applies to JavaCompile
- reproducible builds
basics
~10 sSet 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 sA 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// app/build.gradle.kts
kotlin {
jvmToolchain(17)
}
// equivalent low-level form:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}go deeper
Know the one-liner kotlin { jvmToolchain(17) } and that it picks the JDK used to compile.
Explain the Gradle-JDK vs toolchain-JDK distinction and that the Kotlin plugin propagates the toolchain to both Java and Kotlin.
Discuss reproducibility, auto-provisioning fallback, and how AGP's JavaCompile inherits the toolchain language version.
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).