Configuration

This template follows the 12-factor app methodology for configuration management. The core principle is simple: store configuration in environment variables, not in code.

This approach enables the same codebase to run in development, staging, and production with different configurations—without modifying any code.

How django-environ Works

The template uses django-environ to read environment variables with type conversion and defaults:

import environ
env = environ.Env()

# String (default)
EMAIL_BACKEND = env("DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend")

# Boolean conversion
DEBUG = env.bool("DJANGO_DEBUG", False)

# Integer conversion
CONN_MAX_AGE = env.int("CONN_MAX_AGE", default=60)

# List parsing (comma-separated)
ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["example.com"])

# Database URL parsing
DATABASES = {"default": env.db("DATABASE_URL")}

Settings File Layering

Configuration is organized into layered settings files:

config/settings/base.py

Shared settings used by all environments. Reads from environment variables with sensible defaults for optional settings.

config/settings/local.py

Development overrides. Sets DEBUG=True, uses console email backend, enables debug toolbar.

config/settings/production.py

Production hardening. No defaults for secrets—missing required variables raise errors. Enables security headers (HSTS, secure cookies, SSL redirect).

config/settings/test.py

Test optimizations. Uses fast password hasher, in-memory email backend.

The active settings file is determined by DJANGO_SETTINGS_MODULE:

# Development
DJANGO_SETTINGS_MODULE=config.settings.local

# Production
DJANGO_SETTINGS_MODULE=config.settings.production

# Testing
DJANGO_SETTINGS_MODULE=config.settings.test

The .env File

Automatic Secret Generation

When you generate a project, the template automatically creates a .env file with cryptographically secure random values for:

  • POSTGRES_USER — 32-character random string

  • POSTGRES_PASSWORD — 64-character random string

  • DJANGO_SECRET_KEY — 64-character random string

  • DJANGO_ADMIN_URL — Random admin path (e.g., a8f3b2c1d4e5/)

  • CELERY_FLOWER_USER / CELERY_FLOWER_PASSWORD — If Celery is enabled

This ensures every generated project has unique secrets out of the box.

.env vs .env.example

Two environment files exist:

.env.example

Template showing all available variables. Committed to version control as documentation.

.env

Actual configuration with real secrets. Never committed—automatically added to .gitignore.

The DJANGO_READ_DOT_ENV_FILE Setting

This controls whether Django loads the .env file:

READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False)
if READ_DOT_ENV_FILE:
    env.read_env(str(BASE_DIR / ".env"))

Important: OS environment variables always take precedence over .env file values.

  • Docker development: Set DJANGO_READ_DOT_ENV_FILE=True in the .env file. Docker Compose loads this via env_file directive.

  • Production: Set to False (the default). Configure environment variables through your hosting platform instead.

Configuration by Environment

Local Development (Docker)

The recommended development setup uses Docker Compose:

  1. Project generation creates .env with secrets

  2. docker-compose.local.yml loads .env via:

    services:
      django:
        env_file:
          - ./.env
    
  3. All services (Django, PostgreSQL, Redis) share the same environment

The .env file contains:

# PostgreSQL
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=your_project
POSTGRES_USER=<auto-generated>
POSTGRES_PASSWORD=<auto-generated>

# Django
DJANGO_READ_DOT_ENV_FILE=True
USE_DOCKER=yes
DJANGO_SECRET_KEY=<auto-generated>
DJANGO_ADMIN_URL=<auto-generated>/

# Redis (if Celery enabled)
REDIS_URL=redis://redis:6379/0

# Frontend
VITE_API_URL=http://localhost:8000

Local Development (without Docker)

If developing without Docker, you can use direnv for automatic environment loading. The template includes a .envrc file:

dotenv
export DATABASE_URL=postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB

Production Deployment

In production, configure environment variables through your hosting platform:

  • Heroku: Config Vars in the dashboard or heroku config:set

  • AWS: Parameter Store, Secrets Manager, or ECS task definitions

  • Railway/Render: Environment variable settings in dashboard

Required variables (no defaults—deployment fails if missing):

Variable

Description

DJANGO_SECRET_KEY

Long random string for cryptographic signing

DATABASE_URL

PostgreSQL connection string

DJANGO_ADMIN_URL

Admin path with trailing slash (e.g., secret-admin/)

DJANGO_ALLOWED_HOSTS

Comma-separated list of allowed hostnames

Security defaults in production:

  • SECURE_SSL_REDIRECT=True — Redirects HTTP to HTTPS

  • SESSION_COOKIE_SECURE=True — Cookies only sent over HTTPS

  • CSRF_COOKIE_SECURE=True — CSRF token only sent over HTTPS

  • SECURE_HSTS_SECONDS=60 — HTTP Strict Transport Security enabled

Best Practices

  1. Never commit secrets — The .env file is gitignored for a reason

  2. Use platform-native secret management — Heroku Config Vars, AWS Secrets Manager, etc.

  3. Different secrets per environment — Never reuse production secrets in development

  4. Rotate secrets periodically — Especially DJANGO_SECRET_KEY and database passwords

  5. Don’t rely on .env in production — Set DJANGO_READ_DOT_ENV_FILE=False

See Also