Jolta — the hands-off Java version manager
$ cd my-service<br>$ jolta pin 21 # writes .java-version<br>$ java -version # → OpenJDK 21, automatically
$ cd ../legacy-app # has .java-version with "8"<br>$ java -version # → 1.8 — no sdk use, no jenv shell, no export JAVA_HOME
Install
Prebuilt binaries for every platform — no Rust toolchain, no runtime, nothing to<br>compile.
macOS Apple Silicon & Intel
Homebrew:
brew install OneAppPlatform/tap/jolta<br>jolta setup
Or the one-line installer:
curl -fsSL https://raw.githubusercontent.com/OneAppPlatform/jolta/main/install.sh | sh
Linux x86_64 & arm64 · static musl, any distro
One-line installer:
curl -fsSL https://raw.githubusercontent.com/OneAppPlatform/jolta/main/install.sh | sh
Or Homebrew on Linux:
brew install OneAppPlatform/tap/jolta<br>jolta setup
Windows x86_64
Download jolta-x86_64-pc-windows-msvc.zip from the<br>releases page, unzip, then:
.\jolta.exe setup<br>Follow the two printed steps: add the shims directory to your user<br>PATH, and add the PowerShell hook line to your $PROFILE.
Verify with a new shell:
jolta doctor
How it works
Jolta puts lightweight shims on your PATH<br>(java, javac, jar, jshell, …) — each one a<br>link to the single jolta binary. Every invocation walks up from the current directory to<br>the nearest .java-version, resolves an installed JDK for it, sets<br>JAVA_HOME, and execs the real tool. Resolution takes ~2 ms, invisible<br>next to JVM startup.
If a project pins a version you don't have, the first invocation<br>downloads it on demand (Volta-style) from the distro's official endpoint —<br>never triggered by merely cd-ing around, safe under parallel builds, and<br>disabled with JOLTA_NO_AUTO_INSTALL=1. Restricted networks can set<br>JOLTA_DOWNLOAD_BASE to serve JDKs from an internal mirror<br>({base}/{vendor}/{version}/{os}-{arch}.{ext}) instead of the vendor<br>endpoints.
Jolta also finds the JDKs you already have: Homebrew,<br>/Library/Java/JavaVirtualMachines, SDKMAN, /usr/lib/jvm,<br>Windows Program Files, and JAVA_HOME__* environment<br>variables.
Pinning
The pin is a plain .java-version file (compatible with jenv and asdf) —<br>commit it to your repo:
jolta pin 21 # this project uses Java 21<br>jolta default 21 # global fallback when a project has no pin<br>Resolution order: JOLTA_JAVA_VERSION env var → nearest<br>.java-version walking up → jolta default → system default JDK.<br>On a machine with no JDK at all, the first java run installs the latest<br>LTS (Temurin) and sets it as your default.
A major pin (21) matches the highest installed build of that major.<br>An exact pin (21.0.2) means exact — never silently substituted, and<br>auto-installed precisely. .sdkmanrc files (java=21.0.2-tem)<br>are honored with vendor mapping when no .java-version claims the<br>directory. jolta catalog (alias search) shows what every distro<br>publishes — latest per distro, per-major comparisons, and @v prefix<br>filters like temurin@21.0 — with installed versions marked.
Distros
A spec can name a JDK distribution as distro@version or<br>distro-version:
jolta pin corretto@21 # this project wants Amazon Corretto 21<br>jolta install graalvm@25 # explicitly fetch a GraalVM JDK
Downloadable: temurin (default), corretto,<br>graalvm, oracle, zulu.
Recognized when matching: those five plus<br>openjdk (Homebrew builds).
A distro-qualified pin is strict — corretto-21 picks an installed<br>Corretto 21 over a Homebrew OpenJDK 21, and auto-installs Corretto if missing.<br>A bare 21 matches any distro.
Point releases: jolta update checks jolta-managed JDKs against the<br>vendors (via redirect filenames — no downloads) and jolta upgrade<br>fetches newer builds and prunes superseded ones. Homebrew/system JDKs stay with<br>their own package managers; resolution picks the highest build of a major, so<br>their upgrades apply automatically.
JAVA_HOME, Maven & Gradle
Two mechanisms keep JAVA_HOME correct:
Shims export it for everything they exec.
The shell hook (installed by setup; zsh, bash, and PowerShell)<br>re-resolves it every time you change directory — covering tools that read<br>JAVA_HOME directly, like Maven, Gradle, and IDEs launched from a<br>terminal. If a pin can't be satisfied the hook unsets<br>JAVA_HOME, so builds fail loudly rather than silently using the wrong<br>JDK.
Don't export JAVA_HOME manually in your profile — the hook owns it. In<br>scripts and CI, use jolta exec mvn ... or<br>eval "$(jolta env)". jolta doctor flags stale values.
Commands
CommandWhat it does<br>jolta setupInstall shims + shell profile setup<br>jolta pin Write .java-version in the current directory<br>jolta default Set the global fallback version<br>jolta install Download a JDK (21, corretto@21, graalvm@25)<br>jolta catalog [x]The JDK catalog: latest per distro/major, @v prefix filters (alias search)<br>jolta updateCheck jolta-managed JDKs for newer point releases<br>jolta upgrade [spec]Upgrade jolta-managed JDKs, pruning old builds<br>jolta uninstall Remove a jolta-managed JDK<br>jolta listList visible JDKs with distro, star the active one<br>jolta jdksMachine-readable list: major / version / distro /...