Environment Variables and PATH, Explained
What environment variables actually are, why they hold config and secrets, and how PATH decides which binary runs when you type a command.
Type node and the right program runs. Set DATABASE_URL and your app connects without a single credential in the source. Both of those are environment variables doing quiet work, and understanding them removes a whole category of confusing errors.
What an environment variable is
An environment variable is a named string the operating system attaches to a running process. Each process gets its own set, stored as simple KEY=value pairs — there are no numbers, booleans, or nested objects at this level, just text. Your program reads them through whatever its language exposes: process.env.HOME in Node, os.environ["HOME"] in Python, $HOME in a shell.
The detail that makes them useful is inheritance. When a process starts a child process, the child receives a copy of the parent’s environment. Your shell has an environment; every command you launch from it inherits that environment; anything those commands launch inherits it in turn. This is why exporting a variable in your terminal makes it visible to the programs you then run there — and why it vanishes when you close the terminal, since that process and its environment are gone.
A few names show up almost everywhere. HOME points at your home directory. USER (or USERNAME on Windows) holds your login name. SHELL names your default shell, PWD your current directory, and LANG your locale. You rarely set these yourself; the system populates them at login.
You set your own variables in a few standard ways. In a shell, export NAME=value makes the variable available to child processes for that session (plain NAME=value without export keeps it local to the shell itself). To persist it, add the export line to a startup file like ~/.bashrc or ~/.zshrc. For applications, a .env file holds project-specific values that a loader reads at startup. In CI and production, the same values are injected as pipeline secrets or platform-managed environment settings.
Why config and secrets live here
The reason this pattern is everywhere is separation. Your code describes behavior; the environment describes the situation it runs in — which database, which API key, which log level. Keeping those apart means the exact same build runs in development, staging, and production with nothing changed but the environment around it.
This is the idea behind the “config in the environment” rule popularized by the Twelve-Factor App methodology: anything that varies between deploys should live in the environment, not in the code. The practical payoff is concrete. Secrets stay out of version control, so a leaked repository does not leak your production keys. Rotating a credential is an environment change and a restart, not a code change and a redeploy. And there is no risk of a developer’s local database URL accidentally shipping to production, because the URL was never in the code to begin with.
PATH: how the shell finds commands
PATH is the single most consequential environment variable, and it works exactly like the others — it is just a string. Its value is a list of directories joined by colons on macOS and Linux (semicolons on Windows):
$ echo $PATH/usr/local/bin:/usr/bin:/bin:/opt/homebrew/binWhen you type a bare command like git, the shell does not search your whole disk. It walks the directories in PATH from left to right and runs the first executable named git it finds. If it reaches the end of the list without a match, you get the familiar command not found. That error is rarely about a missing program — usually the binary exists but its directory is not on PATH. (You can ask the shell which file it would actually run with which git or, in many shells, type git.)
To make a new tool runnable, you add its directory to PATH. Prepending puts it ahead of everything else:
export PATH="$HOME/.local/bin:$PATH"The order matters more than it looks.
FAQ
FAQ
Why does my variable disappear when I open a new terminal?+
What is the difference between setting NAME=value and export NAME=value?+
Are .env files automatically loaded by the operating system?+
Related reading
2026-06-04
ACID vs BASE: What Database Guarantees Actually Promise
ACID and BASE describe two ends of a tradeoff between strict correctness and scalable availability. Learn what each guarantee means, when each fits, and why most modern databases sit somewhere in between.
2026-06-04
Big-Endian vs Little-Endian
Byte order explained: how big-endian and little-endian lay out multi-byte numbers in memory, why network protocols pick one, and when the difference actually bites you.
2026-06-04
Big-O Notation in Plain English
Big-O describes how an algorithm's runtime or memory grows as input grows. Learn the common classes — O(1), O(log n), O(n), O(n log n), O(n^2), O(2^n) — with plain examples.
2026-06-04
CORS in Plain English: Why the Browser Blocks Your Fetch
A clear walkthrough of CORS and the same-origin policy — what an origin is, why your fetch fails, how servers opt in, and the big misconception about who CORS actually protects.
2026-06-04
Floating Point: Why 0.1 + 0.2 Is Not 0.3
Type 0.1 + 0.2 into almost any language and you get 0.30000000000000004. Here is why IEEE 754 binary floating point does that — and how to handle it correctly.
Get the best tools, weekly
One email every Friday. No spam, unsubscribe anytime.