You’ve set DATABASE_URL in your .env file. You’ve exported it in your shell. But your application still can’t find it. Sound familiar?

Environment variable issues are one of the most common — and frustrating — debugging sessions. Here’s a systematic guide to finding and fixing the problem.

The Quick Checklist

Before diving deep, check these common culprits:

  1. Did you restart your application? Environment variables are read at process start
  2. Are you in the right shell session? Variables exported in one terminal don’t exist in another
  3. Is your .env file in the right directory? Most libraries look in the current working directory
  4. Did you spell it correctly? DATABASE_URL vs DATABSE_URL happens more than you’d think

Python: The os.environ Mystery

Problem: KeyError When Accessing Variables

1
2
import os
database_url = os.environ['DATABASE_URL']  # KeyError!

Fix 1: Check if the variable exists first

1
2
3
4
5
6
7
8
import os

# Safe access with default
database_url = os.environ.get('DATABASE_URL', 'sqlite:///default.db')

# Or check explicitly
if 'DATABASE_URL' not in os.environ:
    raise RuntimeError("DATABASE_URL environment variable is required")

Fix 2: Load your .env file properly

The os module doesn’t read .env files automatically. You need python-dotenv:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Install: pip install python-dotenv

from dotenv import load_dotenv
import os

# Load BEFORE accessing variables
load_dotenv()  # Loads from .env in current directory

# Now this works
database_url = os.environ.get('DATABASE_URL')

Common mistake: Calling load_dotenv() after you’ve already tried to read the variable.

Problem: Variables Load Locally But Not in Production

Your .env file isn’t (and shouldn’t be) deployed to production. Check how your hosting platform handles environment variables:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Heroku
heroku config:set DATABASE_URL=postgresql://...

# Railway, Render, Fly.io
# Use their dashboard or CLI

# Docker
docker run -e DATABASE_URL=postgresql://... myapp

# Kubernetes
kubectl create secret generic app-secrets \
  --from-literal=DATABASE_URL=postgresql://...

Node.js: Why process.env Is Empty

Problem: process.env.DATABASE_URL is undefined

1
console.log(process.env.DATABASE_URL);  // undefined

Fix: Use dotenv at the very start

1
2
3
4
5
// This must be the FIRST line in your entry point
require('dotenv').config();

// Now environment variables are available
console.log(process.env.DATABASE_URL);

For ES modules:

1
2
3
4
5
6
// Option 1: Import with side effects
import 'dotenv/config';

// Option 2: Explicit loading
import dotenv from 'dotenv';
dotenv.config();

Common mistake: Importing other modules before dotenv:

1
2
3
4
5
6
7
// WRONG - database.js might access process.env before dotenv loads
import { db } from './database.js';
import 'dotenv/config';

// RIGHT - load dotenv first
import 'dotenv/config';
import { db } from './database.js';

Docker: The Container Isolation Problem

Problem: Variables Set on Host Don’t Exist in Container

Containers are isolated. Your host’s environment variables don’t automatically transfer.

Fix 1: Pass variables explicitly

1
2
3
4
5
# Single variable
docker run -e DATABASE_URL=$DATABASE_URL myapp

# From a file
docker run --env-file .env myapp

Fix 2: Use Docker Compose

1
2
3
4
5
6
7
8
9
# docker-compose.yml
services:
  app:
    build: .
    environment:
      - DATABASE_URL=postgresql://db:5432/myapp
    # Or from a file
    env_file:
      - .env

Problem: Variables Work in docker run But Not in docker-compose

Check your .env file format:

1
2
3
4
5
# WRONG - quotes become part of the value
DATABASE_URL="postgresql://localhost/myapp"

# RIGHT - no quotes needed
DATABASE_URL=postgresql://localhost/myapp

Also verify the file doesn’t have Windows line endings (CRLF). Convert with:

1
sed -i 's/\r$//' .env

Shell: Why export Didn’t Work

Problem: Variable Set in Script Doesn’t Persist

1
2
# setup.sh
export DATABASE_URL=postgresql://localhost/myapp
1
2
./setup.sh
echo $DATABASE_URL  # Empty!

Scripts run in a subshell. Exports don’t affect the parent shell.

Fix: Source the script

1
2
source setup.sh  # or: . setup.sh
echo $DATABASE_URL  # Works!

Problem: Variable Set But Application Can’t See It

Did you export it?

1
2
3
4
5
# WRONG - only visible in current shell
DATABASE_URL=postgresql://localhost/myapp

# RIGHT - visible to child processes
export DATABASE_URL=postgresql://localhost/myapp

Debugging Tips

Print all environment variables:

1
2
3
4
# Python
import os
for key, value in os.environ.items():
    print(f"{key}={value}")
1
2
// Node.js
console.log(process.env);
1
2
# Shell
printenv | grep DATABASE

Check where your app is looking:

1
2
3
import os
print(f"Current directory: {os.getcwd()}")
print(f".env exists: {os.path.exists('.env')}")

The Bottom Line

Environment variable issues almost always come down to:

  1. Timing — loading variables after you need them
  2. Scope — variables not reaching the right process
  3. Location — looking for .env in the wrong directory
  4. Format — typos, wrong syntax, or encoding issues

When in doubt, add debug logging to confirm what your application actually sees. The bug is usually simpler than you think.