A command line tool that helps you install and manage multiple Java versions on your machine.
For now the simplest way to install jvm is to use JBang:
jbang app install jvm@codejiveSee:
jvm --helpjvm delegates JDK discovery and installation to the devkitman library. When you request a Java version (e.g. jvm install 17), resolution follows a three-tier cascade:
17— interpreted as17+, meaning version 17 or newer (open-ended)17!— exact major version 17 onlytemurin-21.0.3— a provider-specific JDK identifier (matched by ID, not version)
Providers are queried in fixed registration order:
current— the JDK running the current processdefault— the JDK set as the global default (~/.jbang/currentjdksymlink)javahome— the JDK pointed to byJAVA_HOMEpath— the JDK found onPATHlinked— manually linked JDK installationsjbang— JBang-managed JDKs (supports install/uninstall)- Platform-specific providers (
multihome,sdkman,scoop,brew,mise,linux)
The first provider that returns a matching installed JDK wins. There is no cross-provider sorting or "pick the best version" logic — provider priority alone determines the result.
Run jvm list-providers to see which providers are active on your system.
When no installed JDK satisfies the request and the request is open-ended below version 21 (the configured default), the system redirects to version 21 instead of downloading the minimum satisfying version. For example, jvm install 11 (interpreted as 11+) with no local JDKs available will install JDK 21, not 11.
Exact requests bypass this: jvm install 11! will always install exactly version 11.
If the default version itself cannot be resolved (e.g. the download API doesn't offer it), the system aggregates all downloadable JDKs from all installable providers, filters by the original minimum version, and selects the highest available.
- Installed JDKs always take priority over downloads, regardless of version
- Open-ended requests get upgraded to the default version (21) when nothing is installed locally
- Exact requests are honored literally — no version upgrading occurs
- Installation is lazy — resolution may identify a downloadable JDK without downloading it until explicitly needed
- The
.jvmrcfile in the current directory (or home directory) can specify a default version viajava=<version>, used when no version argument is provided
- Java 11+ — required to compile and run (
JAVA_HOMEmust be set) - Maven — provided via the included wrapper (
mvnw/mvnw.cmd), no separate install needed
Full build with formatting and tests:
./mvnw spotless:apply clean verifyQuick build, skipping tests:
./mvnw clean package -DskipTestsThe build produces two JARs in target/:
jvm-<version>.jar— thin JAR (no bundled dependencies)jvm-<version>-cli.jar— fat JAR, runnable directly
java -jar target/jvm-<version>-cli.jar --help
java -jar target/jvm-<version>-cli.jar --version
java -jar target/jvm-<version>-cli.jar listOr use the assembled launcher from target/binary/bin/:
# Linux/macOS
./target/binary/bin/jvm --help
# Windows
target\binary\bin\jvm.bat --helpThe project uses Spotless with Google Java Format (AOSP style).
# Apply formatting
./mvnw spotless:apply
# Check without modifying
./mvnw spotless:checkThe project supports building native executables using GraalVM. This creates a standalone binary with faster startup time and lower memory footprint.
- Install GraalVM (recommended: GraalVM 22.3 or later)
- Set
GRAALVM_HOMEorJAVA_HOMEto point to your GraalVM installation - Install the native-image tool:
gu install native-image
To build a native executable, run:
./mvnw clean package -PnativeThe native executable will be created in target/jvm (or target/jvm.exe on Windows).