Managing configuration and credentials creates constant issues when building applications. Hardcoding sensitive values into code carries risk – what if they get checked into source control by accident? Popular solutions like environment variables or dedicated config services can add complexity.
The python-dotenv library solves this simply by externalizing configuration into easy .env files. This keeps secrets out of source code, simplifies setup across environments, and permits easy runtime overrides.
Why Use python-dotenv?
Here are key benefits of using python-dotenv:
Keep Credentials and Configs Out of Version Control
Checking API keys, database passwords, secrets, and other sensitive credentials into version control is risky. Python-dotenv allows defining these as variables in a .env file, which you can exclude from version control.
A common pattern is creating a .env.template
file with placeholders for all variables needed, but no real values. Developers then create a local .env
from this template and populate it.
Simplify Configuration Across Environments
Managing separate configs for local development, staging, production, etc. can prove difficult. With python-dotenv, you just point to a different .env
file per environment:
# Local development
load_dotenv(.env)
# Staging
load_dotenv(.env.staging)
No code changes needed!
Simple Setup
Getting started with python-dotenv requires just a few lines:
import os
from dotenv import load_dotenv
load_dotenv() # Load vars
api_key = os.getenv("API_KEY") # Use vars!
The variables load from .env
into os.getenv()
and os.environ
.
Creating and Loading .env Files
To use python-dotenv, first create a .env
file. This typically goes in the project root.
Best practice is defining a variable structure upfront:
APP_ENV=local
DEBUG_MODE=true
DB_HOST=127.0.0.1
DB_NAME=devdb
Next call load_dotenv()
early when the app starts:
“`python
import os
from dotenv import load_dotenv
load_dotenv() # Load .env vars
This parses `.env` and loads keys/values into the environment. You access them via `os.getenv()`:
python
db_host = os.getenv(“DB_HOST”) # Gets 127.0.0.1
### Ignoring .env from Version Control
To prevent checking secrets into version control, add `.env` to your `.gitignore`:
.gitignore
.env
You may also create a checked-in `.env.template` file that defines variable structure sans values.
## Variable Priority and Overrides
Python-dotenv loads variables at lowest precedence. This permits other definitions like session environment variables or command line arguments to override `.env` values if needed.
The precedence order is:
1. **Command Line** - Highest priority
2. **Session Environment** - Overrides `.env` variables
3. **.env File** - Lowest priority
For example, if `DEBUG=true` exists in `.env` but gets manually set to `false` at runtime, the manual variable takes effect.
This allows overriding configs per environment without changing code.
## Interpolation and Variable Substitution
Dotenv files support interpolating variables when building values:
API_URL=https://api.server.com
API_FULL_URL=${API_URL}/v1/query
“`
Here API_FULL_URL
references API_URL
to build a full value. This reduces duplication.
Managing Production
In production deployments, .env
files may not always store credentials. Solutions like Kubernetes secrets or cloud-based variable injection are common.
The python-dotenv benefit is no code change is needed. The load_dotenv()
call does nothing in production, while session/environment variables take precedence. This enables a single codebase working across all environments.
Conclusion
By externalizing environment-specific configuration into easy .env
files, python-dotenv streamlines configuration across projects and environments.
To start:
- Install python-dotenv
- Create
.env
with variables - Call
load_dotenv()
to load into app!
Python-dotenv removes hardcoding credentials while managing configs safely across environments. Give it a try in your next Python application!
Frequently Asked Questions
How do I ignore .env
from version control?
Simply add .env
to your .gitignore
file. This will exclude it from Git tracking.
What happens if a variable isn’t defined in .env
?
Using os.getenv()
will return None
. With dictionary-style access like os.environ[]
, a KeyError
gets raised.
Can I use interpolation for non-string variables?
Yes, interpolation works for any value type defined in .env
.
Is python-dotenv compatible with frameworks like Flask and Django?
Absolutely! The library is framework-agnostic. Just ensure load_dotenv()
gets called early at startup.
How do I handle production secrets?
Solutions like cloud secret managers and Kubernetes secrets are preferred. Python-dotenv allows falling back to environment variables.