skip to content

Local JDK Detection

How Gradle discovers installed JDKs from SDKMAN, asdf, and OS locations, and the properties that add paths or disable detection. Interviewers ask because auto-detection surprises people on shared CI machines.

on this pageshow

questions

5

What does Gradle's local JDK auto-detection do, and where does it look for installed JDKs?

level: juniorimportance: must knowfreq 55%

answer

  1. discovers installed JDKs, doesn't download
  2. SDKMAN / asdf / Jabba / Homebrew / OS dirs
  3. auto-detect=true by default
  4. probes vendor + version + arch
  5. feeds the toolchain registry

basics

~10 s

Gradle scans well-known locations for installed JDKs so a declared toolchain can be matched to a local JDK without you configuring paths. It checks SDKMAN, asdf, Jabba, Homebrew, and standard OS install directories.

solid answer

~40 s

When you declare a Java toolchain (a required Java language version/vendor), Gradle needs an actual JDK to satisfy it. **Auto-detection** is the mechanism that discovers JDKs already installed on the machine so Gradle can pick a matching one instead of downloading. By default (`org.gradle.java.installations.auto-detect=true`) Gradle probes common install managers and OS locations: SDKMAN (`~/.sdkman/candidates/java`), asdf-java, Jabba, Homebrew/Linuxbrew cellars, the Gradle-managed JDK directory, and standard OS paths (e.g. `/usr/lib/jvm`, `/Library/Java/JavaVirtualMachines`). It also reads JDKs pointed to by `JAVA_HOME` and other env vars when configured. Each discovered JDK is probed (vendor, version, architecture) and entered into the toolchain registry. If no installed JDK matches the toolchain spec, Gradle falls back to auto-provisioning (downloading), unless that is disabled.

code

toml · 4 lines
toml
# gradle.properties
org.gradle.java.installations.auto-detect=true
org.gradle.java.installations.paths=/opt/jdk-17,/opt/jdk-21
org.gradle.java.installations.fromEnv=JDK17_HOME,GRAALVM_HOME

go deeper

for a junior

Know detection finds already-installed JDKs in common locations and that it's on by default.

for a middle

Name the actual suppliers (SDKMAN, asdf, OS dirs) and distinguish detection from provisioning.

for a senior

Explain probing/caching and how the registry feeds toolchain matching, plus the fallback chain.

for a principal

Reason about cross-machine reproducibility: standardizing detected JDK locations across dev + CI to make toolchain resolution deterministic.

## The problem auto-detection solves A **Java toolchain** is a declaration in your build of "this code must be compiled and run with Java version N (optionally from vendor V)", decoupled from whatever JDK launched Gradle itself. Gradle then has to *find* a real JDK on disk that satisfies that spec. **Auto-detection** is the discovery step: it enumerates JDKs already installed on the machine so a toolchain can be satisfied locally, avoiding a download. ## Where Gradle looks With detection enabled (the default), Gradle queries a set of *installation suppliers*: - **Version managers**: SDKMAN (`~/.sdkman/candidates/java/*`), asdf (`~/.asdf/installs/java/*`), Jabba (`~/.jabba/jdk/*`). - **Package managers**: Homebrew / Linuxbrew cellars. - **OS standard locations**: `/usr/lib/jvm` (Linux), `/Library/Java/JavaVirtualMachines` (macOS), the Windows registry / Program Files JDK dirs. - **Gradle's own provisioned JDKs**: the directory where auto-provisioning downloads land (`~/.gradle/jdks` by default). - **Environment variables**: `JAVA_HOME`, and any vars you opt into via `org.gradle.java.installations.fromEnv`. - **Explicit paths**: anything listed in `org.gradle.java.installations.paths`. ## Probing Each candidate directory is *probed* — Gradle runs a small introspection to learn the JDK's Java version, vendor, and architecture. Results are cached so repeated builds are fast. The probed set forms the **toolchain registry** that the toolchain resolver matches against. ## Controlling it ```properties # gradle.properties or -D flags org.gradle.java.installations.auto-detect=true # default; scan known locations org.gradle.java.installations.paths=/opt/jdk17,/opt/jdk21 org.gradle.java.installations.fromEnv=JDK17,GRAALVM_HOME ``` Detection finds JDKs; the **toolchain spec** (declared elsewhere) selects which one to use. If nothing matches and detection plus explicit paths come up empty, Gradle moves to auto-provisioning (a separate, downloading mechanism) unless that too is turned off. ## Why it matters Detection is what makes "declare a toolchain once, build reproducibly across dev laptops and CI" practical: each machine resolves the same logical Java version against whatever it has installed.

  • What happens if detection finds no JDK matching the declared toolchain?
    Gradle falls back to auto-provisioning (downloading via a resolver such as Foojay), unless auto-provisioning is disabled, in which case the build fails with a 'no compatible toolchains' error.
  • Does detection use the JDK that started Gradle?
    That JDK is one of the discovered installations, but the toolchain is matched against the *spec*, not assumed to be the launching JVM — the whole point is to decouple build code from the runtime that ran Gradle.

Detection is like checking which tools you already own in your garage before driving to the hardware store (provisioning).

saying these in an interview costs you the question

  • Saying detection downloads JDKs — that's provisioning, a separate step.
  • Assuming Gradle always uses JAVA_HOME — the toolchain spec drives selection, not JAVA_HOME.

context

open as a page

How do you tell Gradle about JDKs installed in non-standard locations using org.gradle.java.installations.paths and fromEnv?

level: middleimportance: must knowfreq 45%

basics

~10 s

Set org.gradle.java.installations.paths to a comma-separated list of JDK home directories, or org.gradle.java.installations.fromEnv to a comma-separated list of env-var names whose values are JDK homes. Gradle probes those and adds them to detection.

open as a page

A teammate's build fails with 'No compatible toolchains found' even though they have the right JDK installed. How do you debug the detection?

level: middleimportance: should knowfreq 40%

basics

~10 s

Run ./gradlew javaToolchains to see what Gradle actually discovered. If the JDK isn't listed, it's in a non-scanned location or detection is off — add it via installations.paths/fromEnv or re-enable auto-detect.

open as a page

Why and how would you disable auto-detection with org.gradle.java.installations.auto-detect=false?

level: seniorimportance: should knowfreq 35%

basics

~10 s

Set org.gradle.java.installations.auto-detect=false to stop Gradle scanning managers and OS dirs. You then supply JDKs only via installations.paths/fromEnv. It's used on locked-down CI to make the JDK set deterministic and the build fast.

open as a page

How would you design a team/CI policy for JDK detection so builds are reproducible across dev laptops and pipelines?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Leave detection on for developer convenience but standardize where JDKs live. On CI, disable auto-detection and pin JDKs through a fixed set of fromEnv variables the CI image always exports, so every pipeline resolves the same installations.

open as a page