django-environ: Environment Variables and 12-Factor Django Settings
Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application.
At a glance
- What is it?
- django-environ turns os.environ into typed Django settings and parses DATABASE_URL-style connection strings, replacing per-environment settings files. It is small, MIT licensed, and the documentation is thinner than the feature list suggests.
- Who is it for?
- Adopt django-environ if you run Django across several environments and want one settings.py driven by environment variables, especially if you already deploy with DATABASE_URL and REDIS_URL style strings. Skip it if you need nested or structured configuration, since the documented surface is scalar casting and URL parsing, or if your team has standardised on another loader such as python-decouple.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 13 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem django-environ solves for Django deployments
A Django project that runs in development, staging and production usually ends up with settings.py plus a growing set of unversioned settings_local.py files. Each file repeats most of the same values and diverges in a few. django-environ exists to collapse that into one settings module whose values come from the process environment, following the twelve-factor approach the README cites. The intended user is a Django developer or operator who wants the same code artefact deployed to every environment, with credentials and hostnames supplied at runtime. The README states the goal plainly: you can stop making a lot of unversioned settings_*.py files to configure your app. The package also fills os.environ from a .env file using setdefault, so a real environment variable always wins over the file. That ordering matters in containers, where the platform injects variables and the .env file is only a local convenience.
How Env, read_env and db_url work together
The mechanism is a wrapper object around os.environ. You construct environ.Env with a mapping of key to (type, default), then call the instance like a function to read and cast a value. Casting is the first job: DEBUG=(bool, False) means env('DEBUG') returns a Python bool, and a missing variable returns False rather than raising. Without a default, a missing variable raises Django's ImproperlyConfigured exception, which is the behaviour the README shows for SECRET_KEY. The second job is URL parsing. Values like psql://user:[email protected]:8458/db are parsed into the dictionary shape Django's DATABASES setting expects, which is why env.db() can stand in for a hand-written connection block. The README also notes that the parsed result is a urllib.parse.ParseResult, so the package is not inventing its own URL grammar. Env.read_env loads a file into os.environ with setdefault semantics, meaning existing process variables are not overwritten. There is also environ.FileAwareEnv, which the README describes as optional support for Docker-style file based config variables, the pattern where a secret is mounted as a file and the variable holds its path.
Installing django-environ and a first settings.py
The README points to PyPI for the package, and the project information section states it is tested on Python 3.10 and later. The install is a normal pip install.
pip install django-environAfter that, the README's own example is the shortest path to a working configuration. It builds a BASE_DIR, reads a .env file next to the project, and reads three values with casting and defaults.
import environ
from pathlib import Path
env = environ.Env(
DEBUG=(bool, False)
)
BASE_DIR = Path(__file__).resolve().parent.parent
environ.Env.read_env(BASE_DIR / '.env')
DEBUG = env('DEBUG')
SECRET_KEY = env('SECRET_KEY')With no DEBUG in the environment or the file, DEBUG is False. With no SECRET_KEY anywhere, the call raises ImproperlyConfigured, which is the intended failure for a missing secret. The same example shows how a single DATABASE_URL replaces a connection dictionary, and how a second database can be read from its own variable with a fallback.
DATABASES = {
'default': env.db(),
'extra': env.db_url(
'SQLITE_URL',
default='sqlite:////tmp/my-tmp-sqlite.db'
)
}env.db() reads DATABASE_URL and raises if it is absent; env.db_url('SQLITE_URL', ...) reads the named variable and falls back to the SQLite file. The cache setting follows the same shape, with env.cache() for CACHE_URL and env.cache_url('REDIS_URL') for a named variable.
Where django-environ stops being the right tool
The documented surface is scalar casting plus URL parsing. If your configuration is nested, say a list of allowed hosts with per-host options or a dictionary of feature flags with structure, you are writing your own parser on top, and at that point the library is doing little more than reading strings. The README's list of feature support mentions variables casting and URL variables exploded to Django settings, and nothing about structured formats, so a reader who needs JSON or YAML configuration should not assume it is there. A second boundary is the .env file itself. read_env uses setdefault, so a stale variable exported in your shell or baked into a container image silently wins over the file you are editing, and the symptom is a value that refuses to change. That is correct twelve-factor behaviour and a confusing debugging session if you forget it. Finally, the raising behaviour cuts both ways: env('SECRET_KEY') failing loudly at import time is good in production and annoying in a test suite that imports settings without a full environment. The README does not document a rollback or migration path for settings that were previously split across files, so converting an existing project is manual work.
django-environ compared with python-decouple and python-dotenv
The closest neighbour is python-decouple, which also reads values from an environment file and casts them to Python types. The difference in approach is scope. decouple gives you config objects and leaves Django wiring to you; django-environ ships Django-aware helpers, so env.db() and env.cache() return dictionaries ready for the DATABASES and CACHES settings. If your configuration is mostly DATABASE_URL and CACHE_URL strings, that is real work removed. python-dotenv sits at the other end: it loads a .env file into os.environ and stops there, leaving casting and URL parsing to your own code. That is a reasonable choice if you already have a settings layer you like, and a worse one if you would otherwise write the same parsing by hand in every project. The trade-off is coupling. django-environ knows about Django's settings shapes, so its value is highest in a Django project and near zero in a plain Python service, where python-dotenv or decouple is the lighter dependency. The README itself points to cookiecutter-django as a concrete example of the package in use, which is a fair signal of the kind of project it was built for.
Maintenance, releases and the MIT licence
The repository is not archived, and the last push was on 2026-09-16. Releases are frequent enough to suggest continuing work: v0.12.1 and v0.13.0 both landed in February 2026, and v0.14.0 followed on 2026-06-18. The project is MIT licensed, which in practice means you can use it in closed-source and commercial Django applications, keep the copyright notice, and not publish your own source. That is a permissive licence, not a copyleft one, but it is not legal advice and the LICENSE.txt in the repository is the text that governs. The upgrade cost is low by design: the public surface is the Env class and its methods, and the README describes the same call patterns across the versions listed. The main compatibility constraint is stated in the project information section, which says the package is rigorously tested on Python 3.10+ and lists supported Django versions from 2.2 through 6.0. If you are pinned to an older Python, that is the line to check before adding the dependency. Dependencies are minimal, since the parsing is built on urllib.parse from the standard library.
Editorial conclusion
Adopt django-environ if you run Django across several environments and want one settings.py driven by environment variables, especially if you already deploy with DATABASE_URL and REDIS_URL style strings. Skip it if you need nested or structured configuration, since the documented surface is scalar casting and URL parsing, or if your team has standardised on another loader such as python-decouple. Before committing, verify three things: that your deployment injects real environment variables rather than only a .env file, that your Python is 3.10 or newer, and that the URL schemes you use are covered by the documented parsers, because an unhandled scheme is the failure you will hit first.
Frequently asked questions
How do I install django-environ?
Install it from PyPI with pip install django-environ. The project information section states it is tested on Python 3.10 and later, so check your interpreter version first.
What is django-environ used for?
It reads configuration from environment variables into Django settings, casting values to Python types and parsing connection strings such as DATABASE_URL into the dictionaries Django expects. The README frames it as applying the twelve-factor methodology to Django configuration.
How do I use django-environ in a Django project?
Create an environ.Env instance with your casts and defaults, call environ.Env.read_env on your .env file, then read values with env('NAME') or env.db() for DATABASE_URL. The README's example sets DEBUG=(bool, False) and reads SECRET_KEY without a default so a missing secret raises ImproperlyConfigured.
How is django-environ different from django-decouple?
Both read values from an environment file and cast them, but django-environ ships Django-specific helpers such as env.db() and env.cache() that return settings-ready dictionaries, while decouple leaves that wiring to your own code.
What alternatives to django-environ exist?
python-decouple and python-dotenv cover similar ground. python-dotenv only loads a .env file into os.environ and does no casting or URL parsing, so the choice depends on how much of that work you want the library to do.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/joke2k-django-environ)