Skip to main content

Environment Variable

An environment variable is a named value stored in a process's environment that child processes inherit. Environment variables configure application behaviour without hardcoding values. They are the standard method for passing configuration, secrets, and runtime settings to processes.

Understanding Environment Variables

What Is an Environment Variable in Simple Terms

Every running process on Linux has a set of key-value pairs called its environment. These are not part of the code — they are external configuration that the process can read at runtime. DATABASE_URL, NODE_ENV, PORT, AWS_REGION — all of these are typically environment variables.

This is why the same Docker container can run in development (NODE_ENV=development) and production (NODE_ENV=production) without any code changes — only the environment changes.

How It Works

◈ DIAGRAM
+------------------------------------------+
| Parent process environment |
| NODE_ENV=production |
| PORT=4000 |
| DB_HOST=10.0.2.100 |
+------------------------------------------+
|
fork() + exec()
|
v
+------------------------------------------+
| Child process inherits all variables |
| NODE_ENV=production <- inherited |
| PORT=4000 <- inherited |
| DB_HOST=10.0.2.100 <- inherited |
+------------------------------------------+

Practical Commands

Bash
## View all environment variables
env
printenv
## View a specific variable
echo $NODE_ENV
printenv NODE_ENV
## Set a shell variable (local to current shell, NOT inherited)
MY_VAR=hello
echo $MY_VAR ## works
bash -c 'echo $MY_VAR' ## empty -- not exported
## Export a variable (becomes environment variable, inherited by children)
export MY_VAR=hello
bash -c 'echo $MY_VAR' ## hello -- now inherited
## Set and export in one line
export NODE_ENV=production
export PORT=4000
export DB_HOST=10.0.2.100
## Unset a variable
unset MY_VAR
## Set variable for ONE command only (does not persist)
NODE_ENV=staging node server.js
## NODE_ENV is staging only for this command
echo $NODE_ENV ## whatever it was before
## Load from a .env file
export $(cat .env | grep -v '^#' | xargs)
## Check in a running process
cat /proc/1234/environ | tr '\0' '\n' | grep NODE_ENV
## Variable expansion modifiers
echo ${MY_VAR:-default} ## use default if MY_VAR unset or empty
echo ${MY_VAR:=default} ## assign default if MY_VAR unset
echo ${MY_VAR:?"error"} ## exit with error if MY_VAR unset

Troubleshooting

Symptom Command What to Check
App ignores env var printenv VAR_NAME Variable not exported
Var set but child does not see export VARNAME Must export, not just assign
Secret in env visible to others cat /proc/PID/environ Anyone with access can read it
Security

Environment variables are visible to any user who can read /proc/PID/environ for that process. Never store long-lived secrets like private keys in environment variables for long-running production processes. Use a secrets manager (Vault, AWS Secrets Manager) and inject secrets as files instead.

Remember

export is what makes a shell variable into an environment variable. Without export, the variable exists only in the current shell and is not passed to any child processes, scripts, or commands you run.

Frequently Asked Questions

Why are environment variables preferred over config files for secrets and runtime settings?

Environment variables live in process memory rather than on disk, so they don't get accidentally committed to version control the way a checked-in config file might, and they're natively supported across virtually every language and container runtime without needing a parser. They also let the same built artifact (Docker image, binary) behave differently across dev, staging, and production purely by varying what's injected at startup — no rebuild required, which is central to twelve-factor app design.

What's a common mistake when passing secrets via environment variables in containers?

Environment variables are visible to any process that can read /proc/[pid]/environ, show up in crash dumps and error logs, and are often echoed unintentionally by CI systems or `docker inspect`. For genuinely sensitive values, a mounted secrets file or a dedicated secrets manager (Vault, AWS Secrets Manager) with restricted read access is safer than an env var, even though env vars remain fine for non-sensitive config like log level or feature flags.