Environment variables are one of the most common ways to pass configuration to Linux programs: database URLs, API keys, PATH extensions, locale settings. But there's a lot of subtle confusion around setting them temporarily versus permanently, exporting them versus not, and which config file to use. This guide clears it up.
Listing existing environment variables
There are three ways to list all environment variables. They return similar results with minor differences:
env # Most common — shows exported variables
printenv # Same as env, slightly different formatting
set # Shows ALL variables including shell functions To check a specific variable:
echo $PATH
printenv HOME
echo "Database URL is: $DATABASE_URL" Setting a temporary environment variable
This is the source of most confusion. There are two subtly different ways to set a variable, and they behave differently:
# Method 1: simple assignment (NOT exported)
MYVAR="hello"
echo $MYVAR # prints: hello
bash -c 'echo $MYVAR' # prints: (empty — child process can't see it) This only sets the variable in the current shell. Child processes (like a Python script, a Node app, or a Docker container you launch) won't see it.
# Method 2: export (makes it visible to child processes)
export MYVAR="hello"
bash -c 'echo $MYVAR' # prints: hello The rule: if you want a process you launch from this shell to see
the variable, you need export.
Setting a variable for one command only
Sometimes you want to set a variable just for a single command, without affecting anything else. Put the assignment in front of the command:
NODE_ENV=production node app.js
DEBUG=express:* npm start
DATABASE_URL=postgres://localhost/test pytest tests/ The variable exists only for that one command. The next command won't see it. This is cleaner than exporting globally and forgetting to unset.
Making a variable permanent (for your user)
To set a variable that persists across shell sessions, add it to one of these files:
~/.bashrc— runs for interactive non-login shells (most common)~/.profileor~/.bash_profile— runs for login shells~/.zshrc— equivalent for Zsh users
Add the export at the end of the file:
echo 'export DATABASE_URL="postgres://localhost/mydb"' >> ~/.bashrc The variable takes effect in new shells. To load it in your current shell without opening a new terminal:
source ~/.bashrc System-wide environment variables
For variables that should be available to every user on the system, use
/etc/environment (note: this file does NOT support export
or shell syntax — just KEY=value):
# /etc/environment
DATABASE_URL="postgres://localhost/production"
APP_ENV="production"
JAVA_HOME="/usr/lib/jvm/default-java"
Alternatively, for shell-specific defaults, edit /etc/profile or
create a file in /etc/profile.d/:
# /etc/profile.d/myapp.sh
export MYAPP_HOME="/opt/myapp"
export PATH="$MYAPP_HOME/bin:$PATH" Unsetting a variable
Remove an environment variable with unset:
unset MYVAR
echo $MYVAR # prints: (empty) Setting variables for systemd services
If you're running a service under systemd (Node app, Python worker, etc.), environment
variables set in ~/.bashrc won't be picked up because
systemd doesn't source your shell configs. You need to set them in the unit file:
[Service]
Environment="NODE_ENV=production"
Environment="DATABASE_URL=postgres://localhost/mydb"
ExecStart=/usr/bin/node /app/server.js Or load them from a file (cleaner for secrets):
[Service]
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/bin/node /app/server.js
Then /etc/myapp/env contains KEY=value pairs (no export,
no quotes needed for simple values).
The PATH variable (special case)
$PATH is a colon-separated list of directories the shell searches for
commands. To add a directory:
# Prepend (searched first)
export PATH="/opt/myapp/bin:$PATH"
# Append (searched last)
export PATH="$PATH:/opt/myapp/bin" Always include $PATH in the assignment. Writing
export PATH="/opt/myapp/bin" replaces your entire PATH and breaks
your shell (common mistake — you won't be able to run ls or anything).
Common environment variables you should know
$HOME— your home directory (/root,/home/user)$USER— current username$PATH— directories to search for commands$SHELL— current shell path$PWD— current working directory$LANG— system locale$EDITOR— default text editor (used by git, crontab, etc.)
Debugging environment issues
If a service isn't seeing an environment variable you set, check:
- Did you
exportit? (Required for child processes) - Is the service running under systemd? (Needs
Environment=in unit file) - Did you restart the service after changing the config?
- Is it in the right file? (
~/.bashrcvs~/.profile) - Did you
sourcethe file or start a new shell?
Quick debugging trick — inspect a running process's environment:
cat /proc/$(pgrep -f myapp)/environ | tr '\0' '\n' This shows exactly which environment variables the running process actually sees, regardless of what you configured.