skip to content

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%

answer

  1. paths = comma-separated JDK home dirs
  2. fromEnv = comma-separated env-var NAMES
  3. augments, doesn't replace, detection
  4. fromEnv idiomatic for CI
  5. verify with ./gradlew javaToolchains

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.

solid answer

~40 s

Auto-detection covers common managers and OS dirs, but JDKs in custom locations (a tarball under `/opt`, a CI-provided home) won't be found automatically. Two properties extend the search: - `org.gradle.java.installations.paths` — a **comma-separated list of absolute JDK home paths**. Gradle probes each directly. - `org.gradle.java.installations.fromEnv` — a **comma-separated list of environment-variable names** (e.g. `JDK17,GRAALVM_HOME`). Gradle reads each var's value as a JDK home and probes it. This is the idiomatic way to surface CI-injected JDKs. Set them in `gradle.properties` (project or `~/.gradle`) or pass as `-D` system properties. These *augment* auto-detection rather than replace it — both the scanned and the explicitly-listed JDKs end up in the registry. Each path is still probed for vendor/version, so a wrong or non-JDK path is ignored with a warning rather than breaking the build.

code

toml · 5 lines
toml
# gradle.properties (committed) — names stay stable across machines
org.gradle.java.installations.fromEnv=JDK11,JDK17,JDK21

# ~/.gradle/gradle.properties (per-dev) — absolute homes
org.gradle.java.installations.paths=/opt/jdk-17.0.9,/opt/graalvm-21

go deeper

for a junior

Know the two properties exist and that one takes paths and one takes env-var names.

for a middle

Choose correctly between paths (machine-local) and fromEnv (CI/shared), and verify with javaToolchains.

for a senior

Design committed vs per-machine property placement and combine with auto-detect=false for determinism.

for a principal

Standardize a fromEnv contract across the org's CI images so every pipeline exposes the same JDK variable names.

## Why you need explicit paths Auto-detection knows about *managers* (SDKMAN, asdf, Jabba) and *standard OS directories*. A JDK extracted to an arbitrary path — `/opt/corretto-17`, a vendored tarball in CI, a custom NFS mount — is invisible to those suppliers. The two `installations.*` properties let you register those locations explicitly. ## `org.gradle.java.installations.paths` A comma-separated list of **JDK home directories** (the dir that contains `bin/java`, `lib/`, `release`). Gradle probes each and, if it's a valid JDK, adds it to the toolchain registry: ```properties org.gradle.java.installations.paths=/opt/jdk-17.0.9,/opt/jdk-21.0.2,/nfs/shared/graalvm-21 ``` ## `org.gradle.java.installations.fromEnv` A comma-separated list of **environment-variable names**. Gradle resolves each name to its value and treats that value as a JDK home: ```properties org.gradle.java.installations.fromEnv=JDK11,JDK17,JDK21,GRAALVM_HOME ``` This is the preferred pattern on CI runners (GitHub Actions `setup-java` exports `JAVA_HOME_17_X64` etc.; you list those names). It keeps the build file machine-agnostic — the *names* are stable, the *paths* vary per runner. ## Where to set them - `~/.gradle/gradle.properties` — per-developer machine, not committed. - Project `gradle.properties` — committed, shared (use `fromEnv` here so paths aren't hardcoded). - `-Dorg.gradle.java.installations.paths=...` on the command line — one-off / CI override. ## Interaction with detection These properties **add to** detection; they don't disable it. The combined set is probed once and cached. If you want *only* the explicit paths (deterministic CI), pair them with `org.gradle.java.installations.auto-detect=false`. Invalid entries (typo'd path, not a JDK) are skipped with a log warning — they don't fail the build, which can mask a misconfiguration, so verify with `./gradlew javaToolchains`. ## Verifying ```bash ./gradlew -q javaToolchains ``` The `javaToolchains` report lists every JDK Gradle discovered, its source ("Current JVM", "environment variable 'JDK17'", "configured location"...), version, vendor, and whether it satisfies declared toolchains. This is the first diagnostic when a toolchain won't resolve.

  • What's the difference between paths and fromEnv?
    paths lists the JDK home directories directly; fromEnv lists environment-variable *names* whose values are JDK homes. fromEnv keeps committed config machine-agnostic, which is why it's preferred on CI.
  • How do you confirm Gradle actually picked up a path you configured?
    Run ./gradlew javaToolchains — it reports each discovered JDK and its source (configured location, environment variable, current JVM, etc.).
  • What happens if a configured path is wrong?
    Gradle logs a warning and skips it; the build doesn't fail just for that entry, so misconfigurations can be silent until a toolchain fails to resolve.

saying these in an interview costs you the question

  • Putting a path value into fromEnv (it expects variable names, not paths).
  • Pointing paths at a JRE or the bin/ subdirectory instead of the JDK home root.
  • Assuming these properties replace auto-detection — they add to it unless you also set auto-detect=false.

context