Guides / The SECRET_KEY setting must not be empty
The SECRET_KEY setting must not be empty
Django refuses to start with django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty. On your laptop the key came from a file you didn't deploy. On the server, the setting reads an environment variable that isn't there, so the value ends up empty.
What it means
Django signs sessions, password reset links and cookies with SECRET_KEY. An empty key makes those signatures worthless, so Django stops at startup. It is an empty value that triggers this: a missing variable that your code turns into "" is the usual cause.
Why it happens
- The environment variable isn't set on the server. Your settings do
os.environ.get("SECRET_KEY", ""), and the server has noSECRET_KEY. - The name doesn't match. The server has
DJANGO_SECRET_KEY, the code readsSECRET_KEY. - The key lived in a
.envorlocal_settings.pyfile that is correctly gitignored and so never reached the server. - A build step needs it.
collectstaticin a Docker build imports your settings before any runtime variables exist. - The value is whitespace or only quotes, for example from a secrets file with
SECRET_KEY="".
The fix
Generate a key once. Use a long random value, never a word:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
Set it as an environment variable on the server (or in your platform's secrets store), and read it so that a missing value fails loudly and not silently:
# settings.py
import os
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] # KeyError at startup if it is missing
export DJANGO_SECRET_KEY='paste-the-generated-value-here'
If a build step has to import your settings before the real key exists, give that one command a throwaway value. It never reaches the running app:
DJANGO_SECRET_KEY=build-only python manage.py collectstatic --noinput
Making it stick in production
- Never commit the key. If it ever reached git, even once, treat it as leaked: generate a new one and rotate it.
- Rotate without logging everyone out. Since Django 4.1 you can move the old key into
SECRET_KEY_FALLBACKSwhile the new one is inSECRET_KEY. Sessions and signed data keep working, and you remove the old key after a few weeks. Rotating without a fallback invalidates sessions, password reset links and anything else you signed. - Use a different key per environment, so a leaked staging key can't forge production sessions.
- Check it:
python manage.py check --deploywarns when the key is short, predictable or starts with Django's insecuredjango-insecure-prefix (deployment checklist).
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
SECRET_KEY_FALLBACKS = [k for k in [os.environ.get("DJANGO_SECRET_KEY_OLD")] if k]
Users logged out after every deploy are usually a key that changes on each start: see Django users logged out after every deploy.
Or skip it
Django Cloud stores your settings, including SECRET_KEY, encrypted and never shows them again. Paste them in the dashboard or run djangocloud env push, and they apply to the next release.
pip install djangocloud-cli
djangocloud deploy
Free plans are available for students, AWS Activate startups, open-source, non-profit and research projects. See how Django Cloud compares with other ways to host Django.
Django is a registered trademark of the Django Software Foundation. Django Cloud is not affiliated with or endorsed by it. Found a mistake in this guide? Tell us and we will fix it.