Ever lost a PATH change after you close Terminal?
This guide walks through macOS set environment variables with clear Terminal commands for permanent configuration, covering zsh and bash startup files, launchctl, and system-wide paths.
You’ll get copy-paste exports, where to put them (~/.zshrc vs ~/.zprofile vs ~/.bashprofile), how to make GUI apps see the variable, and quick verification commands.
Read on to stop guessing and make your PATH, JAVAHOME, and other toolchain variables stick across sessions.
Core Methods to Configure Environment Variables on macOS

Step 1: Open Terminal. Step 2: Type export MY_VAR="test_value" and press Return. Step 3: Verify by running echo $MY_VAR. You’ll see test_value printed back. That’s how you set a temporary environment variable on macOS.
The critical syntax rule is no spaces around the equals sign. export VAR=value works. export VAR = value triggers a “bad assignment” error in zsh. For zsh and bash shells (the two most common on macOS), use the export keyword. If you’re running tcsh or csh (rare on modern macOS), use setenv VAR value instead, with a space and no equals sign.
Temporary variables disappear when you close the Terminal window or tab. They’re perfect for one-off commands, testing new PATH entries before committing them to a config file, or running a script that needs a custom JAVAHOME without permanently altering your shell environment. The most common ephemeral use cases are PATH adjustments for Homebrew or Python virtual environments and JAVAHOME overrides to switch JDK versions for a single build task.
After setting a variable, confirm it exists with echo $VAR_NAME, printenv VAR_NAME, or env | grep VAR_NAME. The echo command prints the value directly. printenv VAR_NAME outputs the value or nothing if the variable is unset. env | grep VAR_NAME shows the full VAR_NAME=value line in the context of all environment variables.
Set a simple variable: export MY_VAR="hello"
Prepend to PATH: export PATH="/opt/homebrew/bin:$PATH"
Set JAVA_HOME dynamically: export JAVA_HOME=$(/usr/libexec/java_home)
Pick a specific Java version: export JAVA_HOME=$(/usr/libexec/java_home -v 11)
Add a custom bin directory: export PATH="$HOME/bin:$PATH"
Override a locale: export LANG="en_US.UTF-8"
Permanent macOS Environment Variable Configuration in Zsh

macOS Catalina 10.15, released on October 7, 2019, made zsh the default login shell. Since then, the two most important zsh startup files are ~/.zshrc and ~/.zprofile. The ~/.zshrc file loads every time you open a new interactive Terminal session, making it the recommended location for PATH exports, aliases, and JAVA_HOME. The ~/.zprofile file runs once per login session, similar to the older bash ~/.bash_profile behavior. For most developer setups, placing exports in ~/.zshrc ensures they’re available in every Terminal window you open.
When you edit ~/.zshrc, the changes won’t take effect in currently open shells until you run source ~/.zshrc or open a new Terminal tab. A common pitfall is adding an export to ~/.zprofile when you expect it in every new tab. If you open Terminal and the new tab is not a login shell, ~/.zprofile won’t reload. Another frequent issue is appending to PATH multiple times in ~/.zshrc without guarding against duplicates, which can bloat the PATH variable when you source the file repeatedly in the same session.
macOS also loads /etc/zshrc and /etc/zprofile system wide before the user files, so variables set there can be overridden by your own ~/.zshrc or vice versa depending on order.
Example Zsh Export Block
Open ~/.zshrc in a text editor and add the following lines:
export PATH="/opt/homebrew/bin:$PATH"
export JAVA_HOME=$(/usr/libexec/java_home -v 11)
The first line prepends Homebrew’s binary directory (on Apple Silicon) to the front of PATH, ensuring brew installed tools are found before system defaults. The second line uses macOS’s built in /usr/libexec/java_home utility to locate the installed JDK 11 and set JAVA_HOME dynamically. After saving, run source ~/.zshrc to apply immediately, or open a new Terminal tab. Verify with echo $JAVA_HOME and which java.
Using Bash Profiles on macOS for Environment Variables

Older macOS versions (before Catalina 10.15) used bash as the default shell. If you’re on one of those systems or manually switched back to bash with chsh -s /bin/bash, your persistent environment variables belong in ~/.bash_profile or ~/.bashrc. The .bash_profile file runs for login shells, which is the default behavior when you open Terminal on macOS. The .bashrc file is intended for non-login interactive shells, but macOS Terminal windows are login shells, so .bash_profile is the standard location. Many developers add a line to .bash_profile that sources .bashrc if it exists, allowing shared configuration between systems.
Common session issues arise when you switch from bash to zsh or vice versa. If your PATH is set in ~/.bash_profile and you change your shell to zsh, those exports won’t load unless you also add them to ~/.zshrc. Similarly, if you edit ~/.bashrc expecting changes in Terminal but your shell loads ~/.bash_profile first and doesn’t source .bashrc, the variables won’t appear. Always confirm which file your shell reads by checking echo $SHELL and understanding whether your session is a login or non-login shell.
| File | Loads When | Typical Use | Example Entry |
|---|---|---|---|
| ~/.bash_profile | Login shells (Terminal launch on macOS) | PATH, JAVA_HOME, SDK paths | export PATH=”/usr/local/bin:$PATH” |
| ~/.bashrc | Non-login interactive shells | Aliases, prompt customization | export PS1=”\u@\h:\w\$ “ |
| ~/.zshrc | Interactive zsh shells (every new Terminal tab in Catalina+) | PATH, JAVA_HOME, aliases | export PATH=”/opt/homebrew/bin:$PATH” |
| ~/.zprofile | Login zsh shells (once per login session) | Login-time initialization, one-time setup | export LANG=”en_US.UTF-8″ |
System-Wide and GUI Environment Variables on macOS

Applications launched from the macOS Finder or the Dock don’t inherit environment variables set in shell startup files like ~/.zshrc or ~/.bash_profile. Those files are sourced by Terminal shells, and GUI processes are children of launchd, not your shell. If you need Xcode, IntelliJ IDEA, or another GUI app to see a custom JAVA_HOME or PATH entry, you must configure the variable at the system or user session level using launchctl or a LaunchAgent property list.
To modify the system wide PATH that all shells and some system utilities share, edit /etc/paths (requires root privileges) or add a file to /etc/paths.d/. Each line in /etc/paths is treated as a directory to prepend to PATH. Files in /etc/paths.d/ are concatenated and read in alphabetical order. This approach is useful for ensuring Homebrew’s /opt/homebrew/bin appears in PATH for all users, but it won’t help GUI applications that are already running or that ignore shell configured PATH entries.
For GUI apps, use launchctl setenv VAR value to set a variable for the current login session. This command updates the user’s session environment immediately and affects newly launched GUI applications, but the setting disappears on logout or reboot. To make it persistent across reboots, create a LaunchAgent plist in ~/Library/LaunchAgents/ with an EnvironmentVariables dictionary. For example, save the following as ~/Library/LaunchAgents/com.user.env.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.env</string>
<key>ProgramArguments</key>
<array>
<string>true</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>JAVA_HOME</key>
<string>/Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home</string>
</dict>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Load it with launchctl load ~/Library/LaunchAgents/com.user.env.plist or log out and back in. Verify GUI apps now see the variable by running launchctl getenv JAVA_HOME.
PATH additions for Homebrew or custom binaries: prepending /opt/homebrew/bin or $HOME/bin to PATH
JAVA_HOME for IDEs and build tools: pointing to a specific JDK installation
HTTPPROXY and HTTPSPROXY: routing network requests through a corporate proxy
LANG and locale settings: ensuring GUI editors display UTF-8 correctly
SDK home directories: ANDROIDHOME for Android Studio, NODEPATH for global npm modules
Common PATH and Toolchain Variable Setup on macOS

The order in PATH determines which version of a command macOS finds first. If /usr/bin appears before /opt/homebrew/bin, the system Python or Ruby takes precedence over Homebrew’s versions. Prepend your preferred directory to PATH with export PATH="/opt/homebrew/bin:$PATH" to ensure tools installed by Homebrew are resolved before system defaults. This pattern applies to every toolchain: place the directory you control earliest in the colon separated list.
Homebrew on Intel Macs installs to /usr/local/bin, while Apple Silicon Macs use /opt/homebrew/bin. Python users often need to add $HOME/Library/Python/3.x/bin for pip installed tools. Node and npm typically install global packages to /usr/local/lib/node_modules/.bin or a prefix directory you configure in ~/.npmrc. Java developers rely on JAVA_HOME to point build tools (Maven, Gradle, IntelliJ) to the correct JDK. Ruby version managers like rbenv or asdf require their shim directories early in PATH.
In every case, confirm the correct path with which <tool> or command -v <tool> before locking it into your shell config.
Practical Variable Examples
Homebrew on Apple Silicon:
export PATH="/opt/homebrew/bin:$PATH"
Java Home (dynamic):
export JAVA_HOME=$(/usr/libexec/java_home)
List installed JDKs with /usr/libexec/java_home -V, then pin a version: export JAVA_HOME=$(/usr/libexec/java_home -v 17).
Node and NPM global path:
export PATH="$HOME/.npm-global/bin:$PATH"
Configure the npm prefix first: npm config set prefix ~/.npm-global.
Python user scripts:
export PATH="$HOME/Library/Python/3.11/bin:$PATH"
Replace 3.11 with your installed Python version.
Troubleshooting macOS Environment Variable Persistence

Shell startup files are loaded in a specific order, and later files can override variables set by earlier ones. macOS zsh reads /etc/zshenv, ~/.zshenv, /etc/zprofile, ~/.zprofile, /etc/zshrc, ~/.zshrc, /etc/zlogin, and ~/.zlogin in sequence for login shells. If /etc/zshrc modifies PATH after your ~/.zprofile sets it, the system file wins. Use grep -R "PATH" /etc/z* ~/.z* 2>/dev/null to locate all places where PATH is modified, then adjust ordering or use conditional guards.
Changes to shell config files don’t apply to the current Terminal session until you run source ~/.zshrc or open a new tab. If you edited ~/.zshrc, closed the file, and still see the old PATH, you forgot to source. Login shells (the default for macOS Terminal) load ~/.zprofile and ~/.zshrc, while non-login interactive shells skip ~/.zprofile. If you launch a subshell or use zsh from within zsh, you may be in a non-login shell that doesn’t reload ~/.zprofile. Confirm with echo $0; -zsh indicates a login shell, zsh indicates non-login.
File permissions can prevent shell config from loading if you copied dotfiles from another machine and they have restrictive or broken ownership. Run ls -la ~/.zshrc and ensure the file is owned by your user account. If the file has Windows style line endings (CRLF), zsh may fail to parse it correctly. Convert with dos2unix ~/.zshrc or save it again in a Unix friendly editor.
PATH collisions occur when multiple entries point to the same tools but with different versions, and the wrong one appears first. Check the full PATH with echo $PATH | tr ':' '\n' to see every directory in order.
Wrong file edited: Verify your shell with echo $SHELL and confirm whether you need ~/.zshrc, ~/.bash_profile, or another file.
Syntax errors: Remove spaces around = in export statements; use quotes for values containing spaces.
GUI requirement: Shell dotfiles don’t affect GUI apps; use launchctl setenv or a LaunchAgent plist.
PATH collision: Earlier entries in PATH shadow later ones; reorder with export PATH="/preferred:$PATH".
Shell mismatch: You edited ~/.bash_profile but switched to zsh; variables won’t load unless moved to ~/.zshrc.
Unsourced file: Run source ~/.zshrc or restart Terminal to apply changes to the current session.
Final Words
Set a temp var in Terminal with export VAR=value (no spaces), or setenv VAR value for csh/tcsh, then verify with echo $VAR or printenv. That covers the immediate, session-only methods.
For permanent changes add exports to ~/.zshrc or ~/.zprofile for zsh, or ~/.bash_profile for bash, and use launchctl/LaunchAgents for GUI apps. We also covered PATH and common toolchain tweaks for Homebrew, Java, Node.
If something breaks, check the right file, syntax, sourcing, and your shell type.
This guide should make macos set environment variables simpler and less annoying. You’ve got this.
FAQ
Q: How do I set a temporary environment variable in macOS Terminal?
A: To set a temporary environment variable in macOS Terminal, run export MY_VAR=value (no spaces) for zsh/bash; it lasts only for that shell session and ends when you close the shell.
Q: What is the correct export syntax and how does export differ from setenv?
A: The correct export syntax is export VAR=value (no spaces). export is for POSIX shells (bash/zsh); setenv VAR value is used in csh/tcsh and uses a different command form.
Q: How do I verify a variable is set in the current session?
A: To verify a variable is set, use echo $VAR, printenv VAR, or env | grep VAR; you should see the variable’s value printed, blank output means it’s unset.
Q: Are temporary environment variables persistent and when should I use them?
A: Temporary environment variables are not persistent; they last only for the current shell. Use them for one-off PATH tweaks, single-command JAVA_HOME overrides, quick debugging, or test runs.
Q: How do I make environment variables permanent in zsh?
A: To make variables permanent in zsh, add export lines to ~/.zshrc (interactive) or ~/.zprofile (login), then run source ~/.zshrc to apply immediately without logging out.
Q: When should I use ~/.zshrc versus ~/.zprofile?
A: Use ~/.zshrc for interactive shells you type into (terminal sessions). Use ~/.zprofile for login-time setup. PATH and toolchain exports typically go in ~/.zshrc so interactive tools inherit them.
Q: How do I set persistent environment variables on older systems using bash?
A: To set persistent variables in bash, put exports in ~/.bashprofile (login shells) or ~/.bashrc (interactive), then run source ~/.bashprofile to reload changes immediately.
Q: How do I set environment variables for GUI apps launched from Finder?
A: To set env vars for GUI apps, use launchctl setenv for the session or create a ~/Library/LaunchAgents/*.plist with an EnvironmentVariables dictionary to persist across logins (requires logout/login).
Q: How do I change system PATH so it applies more broadly?
A: To change system PATH for all users, add entries to /etc/paths or /etc/paths.d. Note GUI apps may still need LaunchAgents or a relogin to pick up the updated PATH.
Q: How do I set JAVA_HOME temporarily and permanently?
A: To set JAVAHOME temporarily run export JAVAHOME=$(/usr/libexec/javahome). To make it permanent, add the same export to your ~/.zshrc or ~/.bashprofile and source that file.
Q: How do I ensure Homebrew or node binaries are found before system binaries?
A: To prioritize Homebrew or node, place its bin earlier in PATH, e.g. export PATH=”/opt/homebrew/bin:$PATH” (Apple Silicon) or /usr/local/bin on Intel, then confirm with which or command -v.
Q: What quick troubleshooting checks fix missing or wrong environment variables?
A: Quick troubleshooting checks: confirm $SHELL, ensure you edited the right dotfile, remove spaces around ‘=’, check file permissions, source the file, and grep dotfiles for later overrides.
