The Right Way to Install and Manage Java Versions on macOS

There is a correct way to install Java on macOS. If you don't follow it, everything will probably work just fine... at least until you need to switch which version of Java you're using.

Unfortunately, it's pretty common to want to specify a particular Java version for your project. For example, the version of Gradle used by React Native is incompatible with JDKs newer than 11.

So instead of installing Java any old way, follow these instructions. You'll thank me later.

1. Extract the JDK to the Correct Place

On macOS, the correct place to install a JDK is /Library/Java/JavaVirtualMachines. Untar the JDK as-is into a subfolder of this.

If you did this step right, you'll have a folder named "jdk-11.0.7.jdk." There should also be a Contents/Home subfolder of that:

/Library/Java/JavaVirtualMachines/jdk-11.0.7.jdk/Contents/Home

2. Export JAVA_HOME

The JDK has been extracted to the right place, but it's still not quite ready to use. You've got to set the JAVA_HOME environment variable.

Using the example above, it would look like this:

export
JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-11.0.7.jdk/Contents/Home"

And you're done. macOS has built-in wrappers for Java commands that will first check this environment variable before trampolining over to the JDK specified by it.

It's really handy that this is set via an environment variable because it allows you to, in tandem with tools like direnv, easily switch between JDK versions depending on the project that you're working on.

3. /usr/libexec/java_home (Bonus Step)

macOS also has a utility for finding the location of a JDK. You can read about it via man java_home.

The most useful component is that you can provide java_home a less precise version and let it figure out which specific path to use. This is really helpful if you're setting a project-specific JDK and sharing this configuration with other team members via direnv.

The above example could be rewritten using java_home as:

export JAVA_HOME=$(/usr/libexec/java_home -v 11)

Conclusion

I've often seen weird problems arise on other developers' machines that result from how some old version of Java was installed. If you always follow this pattern, it should save you from some headaches.