skip to content

Version Management

Moving a build between Gradle versions: the upgrade procedure, the JDK and plugin compatibility matrix, and surfacing deprecations before they become removals. Interviewers ask because major upgrades are a recurring and dreaded task.

on this pageshow

explore

questions

15

What is the difference between the JDK Gradle runs on and the Java version your project compiles against, and why does that distinction matter for compatibility?

level: juniorimportance: must knowfreq 60%

answer

  1. daemon JVM vs compile target
  2. each Gradle version supports a run-on JDK range
  3. toolchain languageVersion = compile/test target
  4. Unsupported class file major version
  5. two independent concerns

basics

~10 s

Gradle itself runs on one JDK (the one launching the daemon). Your code can compile/test against a different Java version via toolchains. Each Gradle release only supports running on certain JDKs.

solid answer

~50 s

There are two separate concerns. **Running Gradle**: the Gradle daemon executes on a JVM, and each Gradle version officially supports running only on specific JDK ranges (e.g. Gradle 8.x runs on JDK 8 through 21–23 depending on the minor). **Compiling your project**: independently of that, you can target a different Java version. The modern way is a Java toolchain — `java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }` — which lets Gradle provision/locate a JDK 21 to compile, test, and run your app even if Gradle itself launched on JDK 17. The distinction matters because upgrading your target Java version does not require Gradle to support running on that JDK, and vice versa. Before any upgrade you check the official Gradle compatibility matrix for the run-on range, then set the toolchain for the compile target.

code

kotlin · 7 lines
kotlin
java {
    toolchain {
        // What the project compiles/tests/runs against —
        // independent of the JDK launching Gradle.
        languageVersion = JavaLanguageVersion.of(21)
    }
}

go deeper

for a junior

State that Gradle runs on a JDK and your code can target a different one via toolchains.

for a middle

Explain the run-on supported range vs the toolchain compile target and give the DSL.

for a senior

Discuss decoupling daemon JDK from target, CI implications, and the major-class-version error.

for a principal

Frame org policy: pin the daemon JDK to a supported LTS, standardize toolchains across repos.

## Two independent JVMs When you use Gradle there are two separate Java versions in play, and conflating them is the most common compatibility mistake. ### 1. The JDK Gradle runs on The Gradle daemon is itself a JVM process. Whatever JDK launches it (found via `JAVA_HOME`, the `org.gradle.java.home` property, or the launcher's own JDK) must be a version that *that Gradle release supports*. Each Gradle version has a documented range. For example, Gradle 8.5 added support for running on JDK 21; older Gradle versions will fail or behave unpredictably on a too-new JDK because bytecode/internal APIs change. Running Gradle on an unsupported JDK is the classic cause of `Unsupported class file major version NN` errors. ### 2. The Java version your project targets Independently, your `:compileJava`/`:compileKotlin`/`:test`/`run` tasks can target a different Java version. The recommended mechanism is the **Java toolchain**: ```kotlin java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } ``` With a toolchain set, Gradle locates (or, with a provisioning plugin like Foojay, downloads) a JDK 21 and uses it to compile, test, javadoc, and run — *even if the daemon itself is running on JDK 17*. This decouples "what Gradle runs on" from "what my code targets." ### Why the distinction matters - You can target a bleeding-edge Java version (e.g. 21) while keeping Gradle on a conservative, supported JDK. - You can upgrade Gradle to run on a newer JDK without changing your byte-code target. - CI agents only need *one* JDK that can run Gradle; toolchains supply the rest. ### Before any change Consult the official **Gradle compatibility matrix** for the run-on JDK range of your Gradle version, then set the toolchain `languageVersion` for the compile target. These are answered by two different parts of the matrix.

  • If Gradle runs on JDK 17 but the toolchain is JDK 21, what compiles your code?
    A JDK 21 located or provisioned via the toolchain mechanism compiles/tests/runs the code; the daemon stays on JDK 17.
  • What error typically means Gradle is running on an unsupported (too new) JDK?
    `Unsupported class file major version NN` (or the daemon failing to start) — the Gradle release predates that JDK.

saying these in an interview costs you the question

  • Claiming the JDK that launches Gradle must equal your project's target Java version.
  • Thinking you must upgrade Gradle to target a newer Java byte-code level (toolchains decouple them).

context

open as a page

How do you upgrade the Gradle version used by a project that has the wrapper checked in?

level: juniorimportance: must knowfreq 70%

basics

~10 s

Run ./gradlew wrapper --gradle-version X. This rewrites distributionUrl in gradle-wrapper.properties so the next ./gradlew invocation downloads and uses that version. You never hand-install Gradle.

open as a page

After a build you see: 'Deprecated Gradle features were used in this build, making it incompatible with Gradle N.' What does this tell you and what should you do?

level: juniorimportance: must knowfreq 50%

basics

~20 s

It means your build used something that will be removed in the next major Gradle (version N), so it would break after upgrading. Re-run with --warning-mode all to see the specific deprecations, then fix them.

open as a page

What does Gradle's --warning-mode flag do, and what are its possible values when you're preparing for a major-version upgrade?

level: juniorimportance: must knowfreq 55%

basics

~10 s

--warning-mode controls how Gradle shows warnings (mainly deprecations). Values: all, summary, none, fail. Use all to see every deprecation with details before upgrading to a new major Gradle version.

open as a page

Before upgrading the JDK on your CI agents or bumping Gradle, how do you use the official Gradle compatibility matrix to avoid breakage?

level: middleimportance: must knowfreq 55%

basics

~10 s

Look up your Gradle version in the official compatibility matrix to confirm it supports running on the target JDK before installing that JDK on CI. If not, bump Gradle first.

open as a page

Walk through the two-pass Gradle upgrade procedure and explain why each pass matters.

level: middleimportance: must knowfreq 55%

basics

~10 s

Pass 1: ./gradlew wrapper --gradle-version X bumps distributionUrl. Then build with --warning-mode=all and fix deprecations. Pass 2: re-run ./gradlew wrapper so the new Gradle regenerates gradlew/jar to match itself.

open as a page

Beyond JDK support, why must you also align Gradle with the Kotlin Gradle plugin and Android Gradle Plugin (AGP) versions, and how do you find a compatible set?

level: middleimportance: should knowfreq 45%

basics

~10 s

Each Kotlin plugin and AGP version supports only a range of Gradle versions. Check their own compatibility tables, not just Gradle's JDK matrix, and pick a set where all three overlap.

open as a page

After upgrading, which wrapper files must be committed and why does committing them matter for the team?

level: middleimportance: should knowfreq 45%

basics

~10 s

Commit all four: gradle-wrapper.properties, gradle-wrapper.jar, gradlew, and gradlew.bat. Together they guarantee every developer and CI run uses the exact same Gradle version with zero manual install.

open as a page

You run with --warning-mode all and see a deprecation, but the message doesn't point at your build script. How do you find what actually triggered it?

level: middleimportance: should knowfreq 45%

basics

~10 s

Add --stacktrace to the run. Combined with --warning-mode all, Gradle prints a stack trace for each deprecation, so you can see whether it came from your build script or from a plugin.

open as a page

How does declaring a Java toolchain interact with Gradle's run-on JDK support, and what does it NOT change about compatibility?

level: seniorimportance: should knowfreq 40%

basics

~10 s

A toolchain selects the JDK that compiles/tests/runs your code, independent of the daemon's JDK. It does not change which JDKs your Gradle version is allowed to run on.

open as a page

How would you plan and roll out a Gradle major-version upgrade across many repositories in an organization while keeping CI safe?

level: seniorimportance: should knowfreq 30%

basics

~10 s

Step through minors first, fixing deprecations with --warning-mode=all each hop, then take the major. Pin via the wrapper, verify on a branch in CI, automate the bump with renovate/Dependabot, and verify the distribution checksum.

open as a page

How would you use --warning-mode to make sure no new Gradle deprecations creep into a build between major-version upgrades?

level: seniorimportance: should knowfreq 38%

basics

~10 s

Set --warning-mode=fail (or org.gradle.warning.mode=fail) in CI. The build then fails whenever any deprecation is logged, so a new deprecation from code or a plugin upgrade is caught immediately.

open as a page

What do the `--distribution-type` and `--gradle-distribution-url` options on the wrapper task do during an upgrade?

level: middleimportance: nice to knowfreq 20%

basics

~10 s

--distribution-type bin|all chooses between the binary-only zip and the full (sources + docs) zip written into distributionUrl. --gradle-distribution-url lets you point at a custom/mirror URL instead of resolving from a version number.

open as a page

Where can you configure Gradle's warning mode, and what wins if both gradle.properties and the command line set it?

level: middleimportance: nice to knowfreq 25%

basics

~10 s

Set it via the CLI flag --warning-mode=<mode> or via org.gradle.warning.mode=<mode> in gradle.properties (or as a system property). The command-line flag takes precedence over gradle.properties.

open as a page

As a lead managing many repos, how do you govern Gradle/JDK/plugin compatibility so a JDK or Gradle upgrade doesn't break builds across the org?

level: principalimportance: nice to knowfreq 25%

basics

~10 s

Standardize a matrix-vetted set (Gradle + run-on JDK + Kotlin/AGP), share it via version catalogs/convention plugins, pin daemon JDKs and toolchains, and roll upgrades out in a staged, tested wave.

open as a page