Homebrew doesn’t actually manage Java installations; it just downloads and installs them for you, leaving the actual switching to your operating system’s environment variables.
Let’s get Java installed and switch between versions.
First, we need to see what Java versions Homebrew knows about.
brew search java
This will give you a list of available Java Development Kits (JDKs). You’ll see names like openjdk, openjdk@11, openjdk@17, etc. openjdk usually refers to the latest stable version.
To install a specific version, say OpenJDK 17:
brew install openjdk@17
Homebrew will download and install it. Once it’s done, it will print some instructions. Crucially, it won’t automatically configure your system to use it.
Homebrew installs these JDKs into a directory like /usr/local/opt/openjdk@17/libexec/openjdk.jdk. Your system needs to know where to find the java executable within that directory.
The standard way to manage Java versions on macOS is by setting the JAVA_HOME environment variable. This variable tells Java-based tools (like Maven, Gradle, or even the java command itself) which JDK installation to use.
After installing openjdk@17, Homebrew will tell you something like:
==> Caveats
To install the latest version of this formula, run:
brew install --cask adoptopenjdk
or
brew install openjdk@17
openjdk@17 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternative version of what is already installed in
macOS.
If you need to have openjdk@17 first in your PATH, run:
echo 'export PATH="/usr/local/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc
echo 'export JAVA_HOME="/usr/local/opt/openjdk@17"' >> ~/.zshrc
For the system Java wrappers to find this JDK, run the following:
sudo ln -sfs /usr/local/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk
The JAVA_HOME part is key. Let’s break down those commands:
echo 'export PATH="/usr/local/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc: This adds a line to your shell’s configuration file (.zshrcfor Zsh, or.bash_profilefor Bash) that prepends thebindirectory of your chosen Java version to your system’sPATH. This makes thejavacommand from that specific installation available directly.echo 'export JAVA_HOME="/usr/local/opt/openjdk@17"' >> ~/.zshrc: This sets theJAVA_HOMEenvironment variable to point to the root of the JDK installation.
Important: If you’re using Bash, you’ll want to append these to ~/.bash_profile instead of ~/.zshrc. After modifying your shell’s config file, you need to either close and reopen your terminal, or run source ~/.zshrc (or source ~/.bash_profile) for the changes to take effect.
To verify, run:
java -version
echo $JAVA_HOME
You should see output indicating OpenJDK 17, and $JAVA_HOME should point to /usr/local/opt/openjdk@17.
Now, what if you have multiple versions installed, say openjdk@11 and openjdk@17? You’d follow the same process for each.
Let’s say you have both installed and want to switch to OpenJDK 11. You would remove the existing JAVA_HOME and PATH exports for OpenJDK 17 from your ~/.zshrc (or ~/.bash_profile) and add the ones for OpenJDK 11.
The Homebrew paths for these would typically be:
- OpenJDK 11:
/usr/local/opt/openjdk@11/libexec/openjdk.jdkfor the symlink, and/usr/local/opt/openjdk@11/binfor the PATH. - OpenJDK 17:
/usr/local/opt/openjdk@17/libexec/openjdk.jdkfor the symlink, and/usr/local/opt/openjdk@17/binfor the PATH.
So, to switch to OpenJDK 11, you’d edit ~/.zshrc to contain:
export PATH="/usr/local/opt/openjdk@11/bin:$PATH"
export JAVA_HOME="/usr/local/opt/openjdk@11"
Then run source ~/.zshrc.
The sudo ln -sfs ... command Homebrew suggests is a system-level hook. It creates a symbolic link in a standard macOS Java location (/Library/Java/JavaVirtualMachines/). This allows macOS to list your installed JDKs correctly in System Settings > Java. While JAVA_HOME is what most tools respect, this symlink is good practice for system integration. If you switch versions, you’ll need to update this symlink as well. For OpenJDK 11, it would be:
sudo ln -sfs /usr/local/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk
This command replaces the existing link (if any) with a new one pointing to your desired version. The fs flags mean "force" (overwrite if exists) and "symbolic" (create a symlink).
The most common pitfall is forgetting to source your shell config file or restart your terminal after making changes. If java -version still shows the old version, that’s your first sign.
If you later try to install another version, like openjdk@21, and run into issues, it’s likely because the JAVA_HOME and PATH variables in your shell configuration file are still pointing to an older version, or you forgot to update the symlink in /Library/Java/JavaVirtualMachines/.