Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Sponsored Reserved space — layout preview until AdSense is connected
How-tos

Why Your Web App Needs Environment Variables (And How to Set Them Up)

Learn why environment variables are essential for securing your web app and how to set them up in development, production, and cloud platforms. Includes practical examples for Python, Docker, and Django.

July 2026 8 min read 1 views 0 hearts

You've probably seen code snippets with os.environ.get('API_KEY') or process.env.DATABASE_URL and wondered what the fuss is about. Let me tell you a quick story from PythonSkillset's early days.

We once had a developer accidentally commit a file containing our production database password to a public GitHub repo. Within hours, someone scraped it and tried to log in. That mistake cost us a weekend of panic and a security audit. Environment variables would have prevented that entirely.

What Are Environment Variables, Really?

Think of environment variables as sticky notes your operating system keeps for running programs. When your web app starts, it reads these notes to find sensitive information like database passwords, API keys, or configuration settings.

The beauty? These values live outside your code. They're not in your Python files, not in your JavaScript, not anywhere someone can accidentally commit to version control.

The Three Places You'll Set Them

1. On Your Local Machine (Development)

For local development, you have two solid options:

Option A: The .env file approach Create a file named .env in your project root:

DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
SECRET_KEY=your-super-secret-key-here
API_ENDPOINT=https://api.example.com/v1

Then use a library like python-dotenv to load them:

from dotenv import load_dotenv
import os

load_dotenv()

db_url = os.getenv('DATABASE_URL')
secret = os.getenv('SECRET_KEY')

Option B: Direct terminal export On Linux or macOS:

export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
export SECRET_KEY="your-super-secret-key"
python app.py

On Windows Command Prompt:

set DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
python app.py

2. On Your Production Server

This is where things get serious. Never, ever hardcode credentials in your application code. Here's how to do it right:

For Linux servers (Ubuntu, CentOS, etc.): Edit /etc/environment or add to your user's .bashrc:

export DATABASE_URL="postgresql://prod_user:secure_password@prod-server:5432/proddb"
export SECRET_KEY="a-very-long-random-string"

Then reload with source ~/.bashrc or restart your service.

For Docker containers: Use the -e flag when running:

docker run -e DATABASE_URL="postgresql://..." -e SECRET_KEY="..." myapp

Or better, use a .env file with Docker Compose:

version: '3'
services:
  web:
    image: myapp
    env_file:
      - .env.production

3. On Cloud Platforms (AWS, Heroku, DigitalOcean)

Each platform has its own way, but the concept is identical:

Heroku:

heroku config:set DATABASE_URL=postgresql://...
heroku config:set SECRET_KEY=your-secret

AWS Elastic Beanstalk: Go to Configuration → Software → Environment Properties, or use the CLI:

eb setenv DATABASE_URL=postgresql://... SECRET_KEY=your-secret

DigitalOcean App Platform: In your app's dashboard, find the "Environment Variables" section under Settings. Add them there.

The Golden Rule: Never Commit Secrets

Here's what PythonSkillset learned the hard way. Always add .env to your .gitignore:

# .gitignore
.env
.env.production
*.env

But here's the trick most tutorials skip: create a .env.example file that shows the structure without real values:

DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
SECRET_KEY=change-this-in-production
API_ENDPOINT=https://api.example.com/v1

This way, new developers on your team know exactly what variables they need without exposing secrets.

The Production Gotcha Most People Miss

When you deploy, environment variables behave differently depending on how your app starts. Here's what PythonSkillset learned the hard way:

If you use systemd (common on Linux servers): Your service file needs explicit environment declarations:

[Service]
Environment="DATABASE_URL=postgresql://..."
Environment="SECRET_KEY=..."
ExecStart=/usr/bin/python3 /opt/myapp/app.py

If you use Docker: Never put secrets in your Dockerfile. Use Docker secrets or environment files:

docker run --env-file .env.production myapp

If you use Kubernetes: Use Secrets objects, not ConfigMaps for sensitive data:

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  database-url: "postgresql://..."
  secret-key: "..."

The One Pattern That Saves Headaches

At PythonSkillset, we use a simple pattern that works across all environments:

import os
from dotenv import load_dotenv

# Load .env file only if it exists (development)
load_dotenv()

# Always fall back to environment variables (production)
DATABASE_URL = os.getenv('DATABASE_URL')
SECRET_KEY = os.getenv('SECRET_KEY')

if not DATABASE_URL:
    raise ValueError("DATABASE_URL environment variable is not set")

This way, your code works locally with a .env file and in production with system environment variables. No changes needed between environments.

What About Docker Compose?

If you're using Docker Compose for local development (which PythonSkillset recommends), your docker-compose.yml can reference a .env file:

version: '3'
services:
  web:
    build: .
    env_file:
      - .env
    ports:
      - "8000:8000"

Docker Compose automatically reads the .env file in the same directory. Just make sure that .env is in your .gitignore.

The Security Checklist

Before you deploy, run through this list:

  1. Never hardcode secrets in your source code. Not even temporarily.
  2. Rotate secrets regularly – change database passwords and API keys every 90 days.
  3. Use different values for development, staging, and production.
  4. Log nothing – never print environment variables to logs or error messages.
  5. Audit your team – know who has access to production environment variables.

Real Example: A Django App

Here's how PythonSkillset sets up a Django application:

# settings.py
import os
from dotenv import load_dotenv

load_dotenv()

SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
DEBUG = os.getenv('DJANGO_DEBUG', 'False') == 'True'
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DB_NAME'),
        'USER': os.getenv('DB_USER'),
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': os.getenv('DB_HOST'),
        'PORT': os.getenv('DB_PORT', '5432'),
    }
}

And the corresponding .env file (which never gets committed):

DJANGO_SECRET_KEY=your-secret-key
DJANGO_DEBUG=True
DB_NAME=mydb
DB_USER=admin
DB_PASSWORD=securepassword
DB_HOST=localhost
DB_PORT=5432

The Mistake That Still Happens Too Often

I see developers put environment variables in their Dockerfile. Don't do this:

# BAD - never do this
ENV DATABASE_URL=postgresql://user:pass@prod-server:5432/mydb

Why? Because anyone who can pull your Docker image can run docker inspect and see those values. Use --env-file or Docker secrets instead.

Testing Your Setup

Before you deploy, run this quick sanity check:

import os

required_vars = ['DATABASE_URL', 'SECRET_KEY', 'API_ENDPOINT']
missing = [var for var in required_vars if not os.getenv(var)]

if missing:
    print(f"Missing environment variables: {', '.join(missing)}")
    exit(1)
else:
    print("All environment variables are set")

The Bottom Line

Environment variables are your first line of defense against accidental data leaks. They make your code portable across development, staging, and production. They let you change configuration without touching a single line of code.

At PythonSkillset, we've learned that setting them up properly from day one saves hours of debugging and prevents security nightmares. Start with a .env file locally, use your platform's built-in tools for production, and never, ever commit secrets to version control.

Your future self (and your security team) will thank you.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.