Environment Variables And Secrets Management
Load secrets and configuration from env vars using django-environ or os.environ. Keep secrets out of Git, manage .env files, rotate SECRET_KEY, and understand precedence between env and settings.
1. Introduction
Environment variables are values set outside your code — in your operating system or server — that your Django project reads at runtime. They are the standard way to keep sensitive information like SECRET_KEY, database passwords, and API keys out of your codebase and Git history.
In this guide we will cover two approaches: using Python's built-in os.environ for simple cases, and using django-environ for a cleaner and more practical setup. We will also cover .env files and how to manage secrets safely.
- You should have already split your settings into multiple files. If not, see Multiple Settings Files.
- Your
.venvmust be active and Django 5.2 installed.
2. Why environment variables
Hardcoding sensitive values directly in your settings file causes real problems:
- If you commit
settings.pyto Git, yourSECRET_KEYand database password become part of the Git history — even if you delete them later. - Different environments need different values. Your local database password is not the same as your production one.
- Rotating a secret means editing code and redeploying — with environment variables you just update the value on the server.
3. Using os.environ
Python's built-in os.environ reads values from the system environment. No extra packages needed.
# mysite/settings/prod.py
import os
SECRET_KEY = os.environ['SECRET_KEY']
DB_PASSWORD = os.environ['DB_PASSWORD']
If the variable is not set, Django raises a KeyError and stops. This is intentional — you want to know immediately if a required value is missing.
Use os.environ.get() for optional values with a fallback:
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
DB_PORT = os.environ.get('DB_PORT', '5432')
DEBUG, compare the string value explicitly as shown above — do not rely on truthiness.
4. Using a .env file
Setting environment variables manually in the terminal every time you work on the project is not practical. A .env file stores them in one place and loads them automatically.
Create a .env file at the root of myproject:
# myproject/.env
SECRET_KEY=your-secret-key-here
DEBUG=True
DB_NAME=mydb
DB_USER=myuser
DB_PASSWORD=mypassword
DB_HOST=localhost
DB_PORT=5432
.env to your .gitignore file immediately. This file contains secrets and must never be committed to Git.
# .gitignore
.env
.venv/
__pycache__/
db.sqlite3
5. Using django-environ
django-environ is a package that reads your .env file automatically and handles type casting — so you do not have to manually convert strings to booleans or integers.
Install it
pip install django-environ
pip freeze > requirements.txt
Update base.py
# mysite/settings/base.py
import environ
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env = environ.Env(
DEBUG=(bool, False)
)
environ.Env.read_env(BASE_DIR / '.env')
Use env() in your settings
# mysite/settings/dev.py
from .base import *
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
django-environ automatically reads the .env file and casts values to the correct type. DEBUG comes back as a real boolean, not a string.
.env.example file with the same keys but no real values and commit that to Git. It tells other developers which variables they need to set without exposing any secrets.
# .env.example
SECRET_KEY=
DEBUG=True
DB_NAME=
DB_USER=
DB_PASSWORD=
DB_HOST=
DB_PORT=5432
6. Rotating the SECRET_KEY
If your SECRET_KEY is ever exposed — for example committed to a public Git repository — you must rotate it immediately. Here is how to generate a new one:
python manage.py shell
>>> from django.core.management.utils import get_random_secret_key
>>> print(get_random_secret_key())
# Copy the output and update your .env file
After rotating, all existing sessions and cookies signed with the old key will be invalidated — users will be logged out. This is expected and unavoidable when a key is compromised.
7. Next steps
Your secrets are now safely loaded from environment variables and kept out of your codebase. The next step is to understand AppConfig and the app registry — how Django tracks and initializes all the apps in your project.