Manage Django Secrets With Doppler
Manage Django environment variables and secrets with Doppler: organize projects and configs per environment, inject secrets with doppler run locally and on servers, sync to Heroku, Render, Vercel, or Kubernetes, use service tokens in CI, and rotate safely.
Problem statement
Your Django project's secrets live in several places: .env files on laptops, variables in the hosting dashboard, CI secrets, and a shared password manager entry that nobody trusts is current. Adding a new variable means updating all of them. Doppler is a hosted secrets manager that stores variables per project and environment and injects them into processes, platforms, and CI, so Django keeps reading os.environ while the values come from one place.
- Create a Doppler project with configs for
dev,stg, andprd, and addSECRET_KEY,DATABASE_URL, and the rest. - Locally, run Django with
doppler run -- python manage.py runserver; no.envfile needed. - On servers, install the CLI and start Gunicorn with
doppler run -- gunicorn ..., authenticated by a service token. - On PaaS hosts and Kubernetes, use Doppler's integrations to sync secrets into the platform's native variables or Secrets.
- Give CI a read-only service token for the config it needs, and rotate tokens and secrets on schedule.
Step-by-step solution
1. Organize projects and configs
A Doppler project usually maps to one Django app. Each environment is a config: dev for local work (developers can create personal branch configs from it), stg for staging, and prd for production. Inherit common values and override per config. Settings stay standard:
SECRET_KEY = os.environ["SECRET_KEY"]
DATABASES = {"default": dj_database_url.config(conn_max_age=60)}
2. Use it locally
doppler login
doppler setup # choose project and dev config for this directory
doppler run -- python manage.py runserver
doppler run -- python manage.py migrate
doppler run fetches the config and starts the command with those variables. Developers no longer need a shared .env file, and access can be revoked per person.
3. Run on servers
Create a service token for the prd config and store it on the server as the only secret:
# /etc/systemd/system/shop.service
[Service]
User=deploy
Environment=DOPPLER_TOKEN=dp.st.prd.xxxx
ExecStart=/usr/bin/doppler run -- /srv/app/.venv/bin/gunicorn config.wsgi --bind unix:/run/shop/gunicorn.sock
Better, put the token in a root-readable EnvironmentFile. The CLI can cache the fetched secrets encrypted on disk with a fallback file, so a Doppler outage does not stop restarts.
4. Sync to platforms
Doppler integrations push secrets into Heroku config vars, Render environment groups, Vercel environment variables, AWS Secrets Manager or Parameter Store, GitHub Actions secrets, and others. Changes in Doppler update the platform, which may trigger a redeploy depending on the platform. For Kubernetes, the Doppler operator syncs a config into a Kubernetes Secret, and can restart Deployments when it changes.
5. Rotate and audit
Doppler keeps a history of changes and an audit log. When rotating SECRET_KEY, use Django's SECRET_KEY_FALLBACKS so sessions survive:
SECRET_KEY = os.environ["SECRET_KEY"]
SECRET_KEY_FALLBACKS = [k for k in os.environ.get("SECRET_KEY_FALLBACKS", "").split(",") if k]
Update the values in Doppler, let them sync, restart processes, and remove the fallback after sessions expire.
Explanation
Doppler stores secrets centrally with access control per project and config, and delivers them as environment variables at process start or by syncing into other systems. Because Django already reads configuration from os.environ in twelve-factor style setups, adopting Doppler does not require code changes. The benefits are fewer copies of each secret, revocable access, change history, and consistent values across local, CI, and production.
Edge cases / notes
- Process restarts. Environment variables are read at start; processes need a restart (or a redeploy) to see changed values.
- Build-time variables. Values needed during
collectstaticor Docker builds must be passed into the build explicitly, ideally only non-secret ones. - Outages. Use the CLI's fallback file or platform syncs so a temporary Doppler outage does not block restarts.
Next steps
- Compare approaches in Manage Django Secrets in Production.
- An open-source alternative: Manage Django Secrets With Infisical.
- Prepare for incidents with Respond to Leaked Django Secrets.
FAQ
Does Django need a Doppler library?
No. Doppler injects environment variables; Django reads them with os.environ as usual.
What happens if Doppler is down?
doppler run can use an encrypted fallback file, and platform syncs keep the last values. Configure one of them.
How do servers authenticate to Doppler?
With service tokens scoped to a single config, stored as the only secret on the server.
Can Doppler sync to Kubernetes?
Yes, through the Doppler Kubernetes operator, which keeps a Secret in sync.