Setting environment variables on OS X
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Setting environment variables on macOS depends on where your process starts. Terminal shells, GUI apps launched from Finder, and launch daemons do not share the same initialization files. If you choose the wrong location for an environment variable, everything may look correct in terminal while your app still cannot see it.
Understand Scope Before Editing Files
You should decide the target scope first:
- current shell session only.
- every new shell for one user.
- system service or launch daemon process.
- GUI app started outside terminal.
Using the right scope prevents brittle setups and accidental secret exposure.
Session-Only Variables
For one terminal session, set with export:
This lasts until the shell exits. It is ideal for temporary testing and one-off commands.
Persistent Variables for Terminal Shells
Modern macOS uses zsh by default. Common file choices:
~/.zshrcfor interactive shell settings.~/.zprofilefor login shell settings.
For development variables used in normal terminal work, ~/.zshrc is usually appropriate.
If you still use bash, equivalent files include ~/.bash_profile and ~/.bashrc.
Environment for GUI Apps
A common macOS surprise is that Finder-launched apps do not read your shell config files. If an IDE or GUI app needs variables, shell-only exports may not work.
For user-level persistent GUI process environment, you can use launchctl:
Verify:
This applies to processes in your launch session. You may need to restart apps to pick up changes.
Project-Specific Approach
For team development, avoid putting project secrets in global shell files. Prefer project-local env files and explicit loading in tooling.
Example with a .env file and Node:
This keeps project configuration versioned and easier to share safely across contributors.
Security and Maintenance Practices
Environment variables are convenient but not automatically secure:
- avoid storing long-term secrets in shell history or committed files.
- use secret managers for production credentials.
- keep
.envin.gitignorewhen it contains sensitive values. - audit old variables periodically to remove stale values.
Also document required variables in a template file such as .env.example so new developers can bootstrap quickly without copying random shell snippets.
Debugging Missing Variables
When a process cannot read expected variables, check:
- which shell is active using
echo $SHELL. - whether the config file was sourced.
- whether the process is terminal-launched or GUI-launched.
- whether the variable name has typos or overwritten values.
For process-specific debugging:
This helps confirm what the current process actually sees.
Common Pitfalls
- Adding exports to
~/.zshrcand expecting Finder-launched apps to inherit them. - Storing sensitive secrets in globally readable shell files.
- Mixing bash and zsh config files without knowing which shell is running.
- Forgetting to reload shell configuration after edits.
- Relying on machine-global settings instead of project-local configuration.
Summary
- Environment variables on macOS are scope-dependent.
- Use
exportfor session-only values and shell config files for terminal persistence. - Use
launchctlwhen GUI apps need environment values. - Prefer project-local env files for team workflows and portability.
- Treat secrets carefully and document required variables explicitly. Revisit these settings after major shell or macOS upgrades to keep behavior consistent.

