What Is an Environment Variable? The Plain-English Guide
CodexFuse Team · 2026-11-03T22:03:59.986Z · 12 min read min read
An environment variable is a named value your app can read while it is running. Developers use environment variables to hold API keys, database URLs, feature flags, and app settings — everything that should not be hard-coded into source code.
If you have ever wondered what is an environment variable, really, here is the plain-English version: it is a label stuck on the outside of the box your program runs in. The program never edits the label itself; it just reads whatever the label says at startup.
This guide has environment variables explained from the ground up: how they work, how to set them on Linux and Windows, what the .env file actually is, and the one discipline — never commit secrets — that keeps you safe. The pattern is everywhere: local shells, Docker containers, CI pipelines. If you are setting up containers, our Docker beginner guide shows the runtime where env vars do their heaviest work.
What is an environment variable?
An environment variable is a name-and-value pair that the operating system hands to a program when the program starts. By convention, each entry takes the form name=value, and the program reads the value to change its behavior without changing its code.
Every process gets its own copy of the environment from whatever started it — your shell, a container runtime, a CI runner. That is why the same app can behave differently on your laptop and in production: same code, different labels on the box. The Linux man page for environ(7) puts it simply: by convention, the strings in the environment have the form "name=value".
You already use environment variables every day without thinking about it. HOME is your login directory, PATH is the list of directories your shell searches for programs, and USER is your logged-in name — all documented in the same man page.
Where do environment variables actually live?
They live inside the environment of each running process — the shell, container, or service that started it passes them down at startup. A process cannot see another process's variables, and a change made after startup usually does not reach a process that is already running.
Most apps are configured in one of a handful of places. The values are the same idea everywhere; only the delivery mechanism changes:
| Where you are | How the variables get set | Example |
|---|---|---|
| Local shell (Linux/macOS) | export in the current session, or a line in ~/.bashrc | export API_URL="https://api.example.com" |
| Windows command prompt | setx for permanent user/system variables | setx API_URL "https://api.example.com" |
| Docker container | -e flags or an env file at docker run | docker run -e API_URL="https://api.example.com" myapp |
| Docker Compose | environment: block or env_file: in compose YAML | env_file: .env |
| CI/CD and hosting platforms | Dashboard settings or the platform's secrets store | Repository or project "Environment variables" panel |
| Your app's process | Inherited from its parent at startup — never set directly by your code | process.env.API_URL in Node.js |
On a server, those values often come from the machine itself. If you are renting the machine rather than owning it, our what is VPS hosting guide explains where the environment boundary sits between you and the provider.
How to set environment variables on Linux
Setting environment variables on Linux takes five steps. Here is the whole workflow, from a throwaway session value to a permanent one:
- Set one for the current session. Run
export API_URL="https://api.example.com". It is visible to every program you launch from that shell afterwards. - Read it back. Run
echo "$API_URL"orprintenv API_URL. If you see the value, the shell registered it. - List everything. Run
printenvto see all variables in the current environment. Pipe it tolessif the list is long. - Make it permanent. Add the
exportline to~/.bashrc(or~/.zshrcfor Zsh), then runsource ~/.bashrcso the current shell picks it up. - Set a one-off for a single command. Put the assignment before the command:
API_URL="https://dev.example.com" node app.js. Only that process sees it.
The Linux man page notes that environment variables may be placed in the shell's environment by the export command — that one command is the entire mechanism on Unix. Variables set this way die with the session unless you persist them in a startup file.
How do apps read environment variables?
Each language gives you a simple accessor, and the pattern is universal: Node.js uses process.env, Python uses os.environ, Go uses os.Getenv. The DEV Community guide on the subject puts it plainly: "In Node.js, you access them via process.env. In Python, os.environ. In Go, os.Getenv. The pattern is universal."
The official docs are precise about what those accessors return. Node.js says "the process.env property returns an object containing the user environment," and adds a useful warning: "It is possible to modify this object, but such modifications will not be reflected outside the Node.js process." In other words, your code can read the box's labels, but it cannot rewrite the box for anyone else.
Python's documentation describes os.environ as "a mapping object where keys and values are strings that represent the process environment," giving environ['HOME'] as the classic example. Both languages agree: the values arrive as strings, always. If you need a number or a boolean, your code converts it.
process.env vs dotenv: what is the difference?
process.env is the real environment your Node.js process inherited from the operating system; dotenv is a small module that reads a .env file and copies its entries into process.env for you. One is the thing, the other is a loader for the thing.
The dotenv maintainer describes it exactly this way: "Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env." And it connects the idea to its origin: "Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology."
This distinction matters because dotenv never touches your real OS environment. It just pre-loads the values before your app starts, which is why dotenv is a development convenience and process.env is what your code actually reads in production.
The .env file tutorial: the convention and the rules
A .env file is a plain-text file of KEY=value lines that your tooling loads for you in development. It is a convenience — not the environment variable itself. That is the single most important distinction in this guide: a .env file is not the same thing as an environment variable; it is just one way to define the values that become variables.
The format rules come from the dotenv parsing rules: BASIC=basic becomes the pair BASIC: 'basic', empty lines are skipped, lines beginning with # are treated as comments, and comments may also be added inline. A typical file looks like this:
# .env — local development only, never committed
API_URL="https://api.example.com"
DB_HOST="localhost"
DB_USER="app_user"
DB_PASSWORD="your_password_here"
FEATURE_FLAG_NEW_CHECKOUT="true"
Now the discipline. The dotenv README asks "Should I commit my .env file?" and answers: "No." The official Node.js .gitignore template enforces it with exact lines: # dotenv environment variable files, .env, .env.*, and !.env.example. That last line is the convention: commit a .env.example with placeholder values and comments, so teammates know what to fill in without ever seeing your real secrets.
Are environment variables safe for secrets? Honestly, no.
No — environment variables are a convenience for configuration, not a security boundary. If a .env file gets committed by mistake, copied into a backup, pasted into a chat thread, or served by a misconfigured web server, every secret in it is exposed. Say it plainly: env vars keep secrets out of code, but they do not keep secrets safe by themselves.
The Expo team states the client-side rule sharply: "never store secrets in environment variables that are used in client side code, because any code you add to a website or a mobile app (even if it's added using an environment variable) can be accessed in plain text." For server-side code, they add, "using environment variables for secrets is paramount." Same mechanism, opposite advice — because the threat model is completely different.
The scale of the failure mode is documented. Legba's research on exposed secrets describes the 2024 cloud extortion campaign documented by Palo Alto Networks Unit 42: attackers scanned over 230 million targets for exposed .env files and collected them from at least 110,000 domains, then used leaked AWS keys to create admin roles and ransom S3 buckets. The same report cites GitGuardian's count of 28.65 million new secrets on public GitHub in 2025 alone, up 34 percent year over year.
That is the graduate arc: environment variables teach you the discipline, and when the stakes grow, you move the actual secrets into a real secrets manager. Our Infisical beginner guide picks up exactly where this guide leaves off — encrypted, audited secret storage for teams that have outgrown plain env vars.
What about Windows?
On Windows, the setx command creates or modifies environment variables permanently — it is, in Microsoft's words, "the only command-line or programmatic way to directly and permanently set system environment values." One catch: "variables set with setx are available in future command windows only, not in the current command window," so you open a new terminal to see them.
Windows has one more difference worth knowing: environment variable names are case-insensitive there, while they are case-sensitive on Linux and macOS. The Node.js documentation calls this out directly: "On Windows operating systems, environment variables are case-insensitive." Code that works with process.env.Path on Windows can break on Linux, where only process.env.PATH matches.
The 12-factor rule that started it all
The environment-variable discipline did not come from a framework — it came from The Twelve-Factor App, a 2011 methodology for building software-as-a-service apps. Factor III is the famous one: "Store config in the environment."
It defines config as "everything that is likely to vary between deploys (staging, production, developer environments, etc)," including "resource handles to the database, Memcached, and other backing services," "credentials to external services such as Amazon S3 or Twitter," and "per-deploy values such as the canonical hostname for the deploy." And it states the rule outright: "The twelve-factor app stores config in environment variables (often shortened to env vars or env)."
The test the methodology proposes still works today: could you open-source your app right now without leaking credentials? If your config lives in environment variables and your .env is gitignored, the answer is yes — no code changes needed. That is the whole discipline in one question.
Sources
- The Twelve-Factor App — "III. Config" — the "store config in the environment" principle, config definition, and the env-vars rule: https://12factor.net/config
- Node.js API docs —
process.env— "returns an object containing the user environment"; case-insensitivity on Windows; modifications do not reflect outside the process: https://nodejs.org/docs/latest-v25.x/api/process.html - Python docs —
os.environ— "a mapping object where keys and values are strings that represent the process environment": https://docs.python.org/3.11/library/os.html - dotenv README (GitHub) — "a zero-dependency module that loads environment variables from a
.envfile intoprocess.env"; "Should I commit my.envfile? — No."; parsing rules: https://github.com/motdotla/dotenv - dotenvx README (GitHub) — the
HELLO=Worlddemo of loading a.envfile: https://github.com/dotenvx/dotenvx - github/gitignore — Node.gitignore — the exact lines
# dotenv environment variable files,.env,.env.*,!.env.example: https://raw.githubusercontent.com/github/gitignore/master/Node.gitignore - Microsoft Learn —
setx— "creates or modifies environment variables in the user or system environment"; variables available in future command windows only: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setx - man7.org — environ(7) — by convention, the strings have the form "name=value";
exportplaces variables in the shell's environment;USER,HOME,PATHdefinitions: https://man7.org/linux/man-pages/man7/environ.7.html - Expo blog — "What are environment variables" — the
API_URLdev/production example; "never store secrets in environment variables that are used in client side code": https://expo.dev/blog/what-are-environment-variables - Legba blog — "Exposed Secrets & API Keys in the AI Era" — the 2024 cloud extortion campaign (230M+ targets scanned, 110,000+ domains) via Unit 42; GitGuardian's 28.65 million new secrets on public GitHub in 2025, up 34%: https://www.legba.app/blog/exposed-secrets-api-keys-ai-era
- DEV Community — "Environment Variables Done Right (and Safe)" — the cross-language access pattern (process.env / os.environ / os.Getenv) and the never-commit rule: https://dev.to/binaryjournal/environment-variables-done-right-and-safe-18e9
Frequently Asked Questions
Is a .env file the same thing as an environment variable?
No. An environment variable is a name-and-value pair that a running process sees in its environment; a .env file is just a plain-text file of KEY=value lines that tools like dotenv load for you in development. The file is a convenience, the variable is the thing. In production, variables usually come from the platform or shell, with no .env file involved at all.
Do I need to restart my app after changing an environment variable?
Usually, yes. Processes inherit their environment once at startup, and most running processes must restart before they see an externally changed value. Set the variable, then restart the app or service. If you only need a value for one run, put the assignment before the command — API_URL="https://dev.example.com" node app.js — and it applies to that process only.
Are environment variables secure?
They are safer than hard-coding secrets, but they are not a security boundary. Secrets in env vars can still leak through committed .env files, process listings, error logs, backups, and client-side bundles. Never put secrets in variables that ship to browsers or mobile apps, never commit .env files, and graduate to a real secrets manager like Infisical when the stakes grow.
What is the difference between process.env and dotenv?
process.env is the actual environment your Node.js process inherited from the OS — it is what your code reads. dotenv is a zero-dependency module that reads a .env file and copies its entries into process.env before your app starts. dotenv never changes the OS environment; it is a development loader, not a system setting.
Should I commit my .env file?
No — never. The dotenv README answers this directly: "No." The official Node.js .gitignore template ignores .env and .env.* while explicitly keeping .env.example. Commit the example file with placeholder values and comments, so every developer knows which variables to set without ever seeing your real secrets.

