Setting the PATH
Before you can compile and run Java programs from the command line, your operating system needs to know where javac and java live. That knowledge comes from the PATH environment variable — a list of directories the OS searches whenever you type a command.
What Is the PATH?
Every operating system keeps a special variable called PATH (or Path on Windows). When you type javac HelloWorld.java in a terminal, the OS walks through each directory listed in PATH, one by one, until it finds an executable named javac. If it never finds one, you get the dreaded error:
'javac' is not recognized as an internal or external command (Windows)
bash: javac: command not found (Linux/macOS)
Adding the JDK’s bin folder to PATH fixes this permanently.
Note: The
PATHvariable does not move any files. It simply tells the OS where to look. The JDK stays exactly where you installed it.
Step 1 — Find Your JDK Installation
Before editing PATH you need to know where the JDK was installed. Common default locations:
| Operating System | Typical JDK Location |
|---|---|
| Windows | C:\Program Files\Java\jdk-21 |
| macOS (Homebrew) | /opt/homebrew/opt/openjdk@21 |
| macOS (Oracle installer) | /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home |
| Ubuntu/Debian (apt) | /usr/lib/jvm/java-21-openjdk-amd64 |
| Fedora/RHEL (dnf) | /usr/lib/jvm/java-21-openjdk |
To confirm the exact path after installing, run:
# Windows (PowerShell)
Get-Command javac | Select-Object -ExpandProperty Source
# macOS / Linux
which javac
readlink -f $(which javac) # follows symlinks to the real path
The folder you want is the JDK root — the one that contains a bin sub-directory with javac inside it. This root path is conventionally stored in a separate variable called JAVA_HOME.
Step 2 — Set JAVA_HOME (Recommended)
JAVA_HOME is a convention used by build tools (Maven, Gradle, Ant) and many IDEs. You set it once, then reference it in PATH so you only have one place to update when you upgrade Java.
Windows
- Press Win + R, type
sysdm.cpl, and press Enter. - Click Advanced → Environment Variables.
- Under System variables, click New:
- Variable name:
JAVA_HOME - Variable value:
C:\Program Files\Java\jdk-21(your actual path)
- Variable name:
- Click OK.
macOS / Linux (shell profile)
Add these lines to your shell’s startup file:
- bash:
~/.bashrcor~/.bash_profile - zsh (default on macOS):
~/.zshrc
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
Tip: On macOS with multiple JDKs installed you can use the dynamic helper instead of a hard-coded path:
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
Step 3 — Add the JDK bin Folder to PATH
Windows
- In the Environment Variables dialog, find the existing Path variable under System variables and click Edit.
- Click New and add:
%JAVA_HOME%\bin - Click OK on every dialog to save.
- Open a new Command Prompt (existing windows do not pick up the change) and verify:
javac -version
java -version
Output:
javac 21.0.3
java version "21.0.3" 2024-04-16 LTS
macOS / Linux
Append to the same startup file you edited above:
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH
Then reload the file without restarting your terminal:
source ~/.zshrc # or ~/.bashrc
Verify:
javac -version
java -version
Output:
javac 21.0.3
openjdk version "21.0.3" 2024-04-16
Warning: Placing
$JAVA_HOME/binbefore$PATH(as shown above) ensures your explicitly installed JDK takes priority over any system-managed Java. If you put it at the end, a different Java version already onPATHmay be picked up first.
Verifying the Full Setup
Once PATH is set, run a quick sanity check:
javac -version # compiler — from the JDK
java -version # runtime — from the JRE bundled inside the JDK
jar --version # archive tool
All three executables live in $JAVA_HOME/bin. If any command fails, double-check the spelling of the path and make sure you opened a new terminal after saving the change.
You can also print the full resolved path to confirm which Java the system picks:
# macOS / Linux
which javac # e.g. /opt/homebrew/opt/openjdk@21/bin/javac
# Windows (PowerShell)
(Get-Command javac).Source
Common Issues and Fixes
| Symptom | Cause | Fix |
|---|---|---|
javac: command not found after setting PATH | Terminal was not restarted | Open a new terminal window |
| Wrong Java version printed | An older JDK is earlier in PATH | Move $JAVA_HOME/bin to the front of PATH |
JAVA_HOME is set but javac still not found | Forgot to add $JAVA_HOME/bin to PATH | Add the bin sub-directory, not the root |
| Path with spaces causes errors on Windows | Unquoted path | Use %JAVA_HOME% (the variable), not the raw path with spaces |
macOS shows /usr/bin/javac instead of your JDK | Apple’s shim is first in PATH | Export JAVA_HOME and put $JAVA_HOME/bin before /usr/bin |
Managing Multiple Java Versions
Real-world projects often require different Java versions — a legacy service on Java 8, a new microservice on Java 21. Two popular tools make switching effortless:
- SDKMAN! (macOS / Linux): install and switch JDKs with
sdk install java 21-temandsdk use java 21-tem. - Jabba (cross-platform): similar concept.
Both tools manage JAVA_HOME and PATH automatically, so you never edit a startup file again.
Under the Hood
When your shell starts, it reads its startup file (e.g. ~/.zshrc) and stores JAVA_HOME and PATH as environment variables — key/value pairs held in the shell process’s memory. Every child process (like a javac invocation) inherits a copy of these variables from its parent shell.
On Linux and macOS the kernel’s execve system call passes the environment array to the new process. The C runtime inside javac calls getenv("PATH") to retrieve the string, then splits it on : (or ; on Windows) to get a list of directories. It opens each directory and checks for a file named javac with execute permission. The first match wins — which is why order matters.
On Windows, the Registry stores system-wide environment variables under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment. The PATH you edit in the GUI is read from there. New processes inherit the updated value; existing processes keep their old copy, which is why you must open a new terminal.
Note: IDEs such as IntelliJ IDEA and Eclipse read
JAVA_HOMEat startup to locate the JDK. If you changeJAVA_HOMEafter the IDE is open, restart it to pick up the new value.
Related Topics
- JDK, JRE & JVM — understand the difference between the tools you just put on your PATH.
- Your First Java Program — now that your PATH is set, compile and run your first program.
- How a Java Program Runs — trace the journey from
.javasource to running bytecode. - JVM Architecture — go deeper into the runtime that
javalaunches. - Command-Line Arguments — pass data into your program when you run it from the terminal.