In this post, we will learn how to keep passwords and sensitive values outside our Django code by using a .env file.
Throughout this post, assume the following project structure:
mysite/
mysite/
settings.py
.env
.gitignore
manage.py
What we will do
Create a .env file - Stores private values.
Install django-environ - Allows Django to read and convert values from the .env file.
Update settings.py - Uses environment variables.
Protect .env - Keeps it away from GitHub.
Content
- Why use a .env file?
- Installing django-environ
- Creating the .env file
- Loading .env in Django
- Using values from .env
- Protecting the .env file
- Final checklist
Why use a .env file?
When we start learning Django, it is very common to keep everything inside settings.py.
For example:
SECRET_KEY = "django-insecure-example-secret-key"
DEBUG = True
This works, but it is not a good habit.
If this project is uploaded to GitHub, these values may become public.
A .env file helps us separate private configuration from the source code.
Instead of writing real passwords, API keys or Django secret keys directly in the code, we store them in a private file called .env.
Code stays public.
Secrets stay private.
Installing django-environ
To read values from a .env file in Django, we will use the package django-environ.
This package is useful because it can read values from the environment and convert them into proper Python types, such as strings, booleans, lists and database settings.
pip install django-environ
Creating the .env file
In the root of your Django project, create a file called .env.
It should be in the same folder as manage.py.
mysite/
mysite/
settings.py
.env
.gitignore
manage.py
Now add your private values:
SECRET_KEY=django-insecure-your-secret-key-here
DEBUG=True
Important:
Keep the variable names simple and avoid spaces around the equals sign.
SECRET_KEY=correct
Instead of:
SECRET_KEY = wrong
Loading .env in Django
Open mysite/mysite/settings.py.
At the top of the file, add:
import environ
Then, after BASE_DIR, create the environment object and load the .env file:
env = environ.Env(
DEBUG=(bool, False)
)
environ.Env.read_env(BASE_DIR / ".env")
This tells Django to load the environment variables from the .env file when the project starts.
The line below also tells Django that DEBUG should be converted into a real Python boolean value:
env = environ.Env(
DEBUG=(bool, False)
)
The first value, bool, is the type we want. The second value, False, is the default value used when DEBUG does not exist in the .env file.
Using values from .env
Now we can replace hardcoded values in settings.py.
Instead of:
SECRET_KEY = "django-insecure-your-secret-key-here"
Use:
SECRET_KEY = env("SECRET_KEY")
The value will come from:
SECRET_KEY=django-insecure-your-secret-key-here
For DEBUG, we can also use env():
DEBUG = env("DEBUG")
Because we already configured DEBUG as a boolean, django-environ converts the value automatically.
So this value from .env:
DEBUG=True
becomes a real Python boolean:
True
A clean version with default values can look like this:
SECRET_KEY = env("SECRET_KEY")
DEBUG = env("DEBUG")
The default value for SECRET_KEY is used only if the variable does not exist in the .env file.
At this point, the beginning of your settings.py can look like this:
from pathlib import Path
import environ
BASE_DIR = Path(__file__).resolve().parent.parent
env = environ.Env(
DEBUG=(bool, False)
)
environ.Env.read_env(BASE_DIR / ".env")
SECRET_KEY = env("SECRET_KEY")
DEBUG = env("DEBUG")
ALLOWED_HOSTS = []
settings.py now contains the logic.
.env contains the private values.
Protecting the .env file
The .env file should not be uploaded to GitHub.
Open or create .gitignore and add:
.env
You can also ignore other local development files:
.env
db.sqlite3
__pycache__/
*.pyc
venv/
Keep in mind that
A .env file is not magic security.
It simply helps you avoid writing secrets directly in your source code.
You still need to protect your server, your database and your deployment environment.
Final checklist
- Install django-environ
- Create a .env file
- Move secrets into .env
- Create an env object with environ.Env()
- Load the file with environ.Env.read_env()
- Read values with env()
- Use casting for values like DEBUG
- Add .env to .gitignore
In short:
settings.py contains the logic.
.env contains the secrets.