javm is a fast, cross‑platform Java version manager (fork of jabba) focused on a frictionless install and switch workflow for JDKs on Linux, macOS and Windows.
- Install & switch between multiple JDK distributions (Zulu, OpenJDK, GraalVM, Temurin, etc.) using semver ranges
- Per‑project JDK via
.java-version - Remote discovery through the Foojay DiscoAPI
- Supports semantic version ranges (
1.8.x,~17.0.2,>=21 <22) - Clean removal (
uninstall,deactivate) without touching system JDK - Static Go binary: fast cold start and no additional dependency
You can install javm using the provided install scripts. They automatically detect your platform and architecture, and support different release channels:
latest: install from the latest GitHub Release (default)nightly: install the most recent development build- Specific version: e.g.
v0.1.0
By default, installs the latest release to ~/.javm.
To install the latest release:
curl -fsSL https://javm.dev/install.sh | bashTo install a specific version or channel:
curl -fsSL https://javm.dev/install.sh | bash -s nightly
curl -fsSL https://javm.dev/install.sh | bash -s v0.1.0By default, installs the latest release to %LOCALAPPDATA%\Programs\javm.
To install the latest release:
irm https://javm.dev/install.ps1 | iexTo install a specific version or channel:
iex "& { $(irm https://javm.dev/install.ps1) } nightly"
iex "& { $(irm https://javm.dev/install.ps1) } v0.1.0"To enable javm in your shell, initialize it with javm init <shell> as shown
for your shell below.
Add this to your ~/.bashrc or ~/.zshrc:
eval "$(javm init bash)"Add this to your ~/.zshrc:
eval "$(javm init zsh)"Add this to your ~/.config/fish/config.fish:
javm init fish | sourceAdd this to your profile file:
iex "$(javm init pwsh)" Tip
To check the path to your PowerShell profile file, run:
echo $PROFILEGenerate the CMD wrapper in a directory separate from javm.exe:
mkdir "%LOCALAPPDATA%\javm\cmd" 2>NUL
javm init cmd > "%LOCALAPPDATA%\javm\cmd\javm.cmd"
set "PATH=%LOCALAPPDATA%\javm\cmd;%PATH%"Keep that wrapper directory before the directory containing javm.exe in your
user PATH, then open a new Command Prompt. CMD checks .exe before .cmd
inside the same directory, so placing both files together bypasses the wrapper
and prevents use and deactivate from changing the current session.
When invoking javm from another batch file, use call javm ... so control
returns to the calling script:
call javm use 21
call javm deactivateGenerate the script file using javm init nu:
javm init nu | save -f ~/.local/share/javm/javm.nuAdd this to your config.nu (you can find it by running $nu.config-path):
source ~/.local/share/javm/javm.nuAfter editing your profile or config, restart your shell or reload your profile to apply the changes.
javm ls-remote # list all available JDKs
javm ls-remote zulu@~1.8.60 # narrow by distribution & semver range
javm ls-remote "*@>=1.6.45 <1.9" --latest=minor # show only latest minorsjavm install zulu@1.8 # Zulu OpenJDK 8 (latest matching)
javm install zulu@~1.8.144 # same as zulu@>=1.8.144 <1.9.0
javm install temurin@17 # Temurin 17 LTS
javm install graalvm@21 # GraalVM
javm install openjdk@21 # Upstream OpenJDKTo install a JDK in a new directory outside the managed JAVM_HOME, use
--output. The destination must not exist, and the resulting JDK is unmanaged
until it is linked explicitly:
javm install temurin@21 --output /opt/jdks/temurin-21javm ls # list installed
javm ls --details # include vendor, architecture and path
javm use zulu@1.8
javm use temurin@17
javm deactivate # restore previous JAVA_HOME / PATHCreate a .java-version in your project root:
17
Then:
javm use # picks version from .java-versionjavm alias default 17 # sets default JDK for new shells
javm alias default # shows the alias value
javm unalias defaultjavm current # show the JDK selected in the current shell
javm which temurin@21 # show the selected JDK path
javm which --home temurin@21 # use the platform-specific JAVA_HOME path
javm config list # list effective configuration
javm config get java.default_distribution
javm config set java.default_distribution temurin
javm config unset java.default_distribution
javm discover refresh # refresh the discovery cache
javm default temurin@21 # set the default for newly initialized shellsjavm link system@1.8.72 /Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdkjavm uninstall zulu@1.8javm uses stable exit codes so scripts can distinguish common failure
classes:
| Code | Meaning |
|---|---|
| 0 | Success, including --help |
| 1 | Unexpected or local operation failure |
| 2 | Invalid command usage or arguments |
| 3 | Requested JDK or other resource was not found |
| 4 | Remote service or download failure |
| 124 | Operation timed out |
| 130 | Interrupted with Ctrl+C |
Prerequisite: Go 1.26.x
git clone https://github.com/felipebz/javm
cd javm
go test ./...
go build -o javm .
./javm --helpQ: Does it override my system Java?
No. javm use adjusts your shell PATH and JAVA_HOME in that session.
Q: How do I revert to the system JDK?
Run javm deactivate or open a new shell (if no default alias points elsewhere).
Q: Can I pin a project JDK?
Yes: Create a .java-version with the JDK version then javm use inside that directory.
Q: Why not install “globally”?
Global changes (e.g. system alternatives, registry edits) vary by OS and often require sudo/admin; javm keeps things user‑scoped and portable.
Apache-2.0. See LICENSE.
