skip to content

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