Flexible and secure .env loader for Python projects with support for environment switching, nested project structures, and external configuration directories.
Project description
dotenv-loader
Smart and flexible .env loader for Python applications.
📖 Overview
dotenv-loader provides a flexible yet straightforward way to load environment variables from .env files, tailored specifically for Python applications, including Django, Flask, Celery, FastCGI, WSGI, CLI tools, and more. It supports hierarchical configuration, making it extremely convenient to manage multiple environments (development, testing, production) without manually switching .env files or cluttering code with environment-specific logic.
🚀 Historical Context
Managing environment-specific settings is crucial in modern software development. Standard solutions like python-dotenv simplify loading variables from .env files but lack flexible mechanisms for dynamically switching configurations across multiple deployment environments or nested project structures.
dotenv-loader was created specifically to solve these practical challenges:
- Easily switch environments without changing code or manually managing environment variables.
- Support flexible directory structures (such as monorepos or Django sub-applications).
- Enable clear separation of environment-specific configurations, improving clarity and reducing human error.
✨ Features
-
Hierarchical and prioritized .env file search: dotenv-loader follows a clear and intuitive priority order:
- Explicit path provided via
DOTENVenvironment variable. - Configuration directory (
DOTCONFIG_ROOT) with customizable subdirectories per project and environment stage (DOTSTAGE). - Automatic fallback to
.envfile located directly in the project root.
- Explicit path provided via
-
Dynamic project and stage selection: Quickly switch configurations by setting the
DOTPROJECTandDOTSTAGEenvironment variables, allowing effortless toggling between multiple environments or projects. -
Customizable file names: Use custom
.envfilenames to further separate and manage your configurations.
🔒 Security and Best Practices
Storing .env files separately in a dedicated configuration directory (DOTCONFIG_ROOT) outside your project source tree is a secure and recommended best practice. This approach significantly reduces the risk of accidentally leaking sensitive information (such as API keys, database credentials, etc.) during backups, version control operations, or file transfers. By keeping secrets separate from your codebase, dotenv-loader helps enforce a clear boundary between configuration and code, enhancing security and compliance.
⚙️ Installation
pip install dotenv-loader
🛠 Usage
Basic Usage
By default, dotenv-loader automatically identifies the .env file from the current project's root directory:
import dotenv_loader
dotenv_loader.load_env()
Advanced Usage
import dotenv_loader
# Load environment with custom default settings
# Each parameter is optional and first four can be overridden by environment variables:
dotenv_loader.load_env(
project='mega-project', # - explicitly set project name
stage='production', # - explicitly set stage name
dotenv='./dir/.env.test' # - explicitly set .env file
config_root='~/custom-configs', # - custom config directory
steps_to_project_root=1, # - how many directories up to look for project root
default_env_filename='env', # - change the default '.env' name to you name
override=True # - whether to overwrite existing environment variables
# already defined in os.environ. Use False to preserve
# values already present (e.g. from OS or CI/CD), or
# True to always prefer .env contents.
)
Environment Variables
You can control the behavior of dotenv-loader using the following environment variables:
- DOTENV — Path to the .env file or directory.
- If a full file path is given, it overrides all other options. If the file is not found, a
FileNotFoundErroris raised. - If a directory path is given, the loader will look for an environment file in that directory, based on
default_env_filenameandDOTSTAGE(or fallbackstage).
- If a full file path is given, it overrides all other options. If the file is not found, a
Examples:
DOTENV=/home/user/.env.custom python manage.py
# Uses this exact file; raises an error if not found
DOTENV=~/myconfigs/myproject python manage.py
DOTSTAGE=prod
# Loads ~/myconfigs/myproject/.env.prod
DOTENV=~/configs/project python manage.py # calling load_env(stage='local')
# Loads ~/configs/project/.env.local
DOTENV — Specify an explicit path to the .env file:
DOTENV=/path/to/custom.env python manage.py
DOTPROJECT — Quickly switch between project environments:
DOTPROJECT=test python manage.py
# Loads: ~/.config/python-projects/test/.env
DOTSTAGE — Select a configuration stage within a project (prod, staging, test):
DOTSTAGE=staging python manage.py
# Loads: ~/.config/python-projects/myproject/.env.staging
DOTCONFIG_ROOT — Override the default configuration root directory:
DOTCONFIG_ROOT=~/myconfigs python manage.py
# Loads: ~/myconfigs/myproject/.env
DOTVERBOSE — Print the resolved path of the loaded .env file to stdout:
DOTVERBOSE=1 python manage.py
# Output: Use DOTENV file from: /home/user/.config/python-projects/projectname/.env
Typical Directory Structure
~/.config/python-projects/
└── myproject/
├── .env # Default configuration (typically a symlink to .env.prod)
├── .env.prod # Production configuration. Use explicitly with: DOTSTAGE=prod python manage.py
├── .env.staging # Staging configuration. Use explicitly with: DOTSTAGE=staging python manage.py
└── .env.test # Testing configuration. Use explicitly with: DOTSTAGE=test python manage.py
myproject/
└── manage.py # By default, loads ~/.config/python-projects/myproject/.env
.env # Used only if no .env.* files are found in ~/.config/python-projects/myproject
🧽 .env Resolution Rules and Precedence
dotenv-loader uses a deterministic and secure resolution strategy when selecting the appropriate .env file to load. The logic ensures maximum flexibility while maintaining clarity and safety.
Resolution Rules
- Environment Variables Take Precedence
The following environment variables override their corresponding load_env() arguments:
DOTENVoverridesdotenvDOTPROJECToverridesprojectDOTSTAGEoverridesstageDOTCONFIG_ROOToverridesconfig_root
- Relative Paths Are Context-Aware
- Paths defined in environment variables (e.g.,
DOTENV,DOTCONFIG_ROOT) are resolved relative to the current working directory (PWD, as seen withpwd). - Paths passed directly to
load_env()(e.g.,dotenv,config_root) are resolved relative to the calling script's location, adjusted bysteps_to_project_root.
For example, if manage.py is at ~/projects/proj1/app/manage.py and steps_to_project_root=1, then project_root is considered to be ~/projects/proj1.
- Project and Stage Names Must Be Basenames
Both DOTPROJECT/project and DOTSTAGE/stage must not include slashes. They are treated strictly as simple names (i.e., Path(name).name).
- Highest Priority: Explicit .env Path or Directory
If either DOTENV or dotenv is defined, it takes priority over all other resolution logic.
-
If the value is a full path to a file, that file is loaded directly. If it doesn't exist, a
FileNotFoundErroris raised and no fallback is attempted. -
If the value is a directory path, the loader will only search within that directory, constructing the target filename as
[default_env_filename][.stage], wherestagecomes fromDOTSTAGEor thestageargument.
- Project Name Determination
The project name is determined as follows:
-
If
DOTPROJECTorprojectis defined, its basename is used -
Otherwise, it defaults to the basename of the computed
project_rootdirectory
Note:
The project_root is computed relative to the file that directly calls load_env(), using the steps_to_project_root parameter.
- If
steps_to_project_root=0(default),project_rootis the directory containing the calling file - If
steps_to_project_root=1, it's the parent of that directory, and so on
For example:
If load_env() is called from ~/projects/proj1/app/manage.py and steps_to_project_root=1, then project_root = ~/projects/proj1, and the fallback project name is proj1.
- .env Filename Construction
The .env filename is constructed as:
"[default_env_filename][[.]STAGE]"
where:
default_env_filenameis.envby defaultSTAGEcomes fromDOTSTAGEorstage9 (if defined)
- Primary Search Location
If no explicit file path is provided via DOTENV/dotenv, the loader checks:
[DOTCONFIG_ROOT | config_root] / [DOTPROJECT | project] / [default_env_filename][.stage]
- Fallback Location
If the file is not found in the config directory, a fallback search is performed in the computed project root:
[project_root] / [default_env_filename][.stage]
- Error Handling
If no valid
.envfile is found after all resolution attempts, aFileNotFoundErroris raised. The error message includes a list of all tried paths for easier debugging.
🎯 Use Cases
dotenv-loader is especially useful when:
- Deploying applications to multiple environments (development, testing, staging, production).
- Managing complex directory structures (monorepos or multi-app Django projects).
- Simplifying CI/CD workflows by dynamically selecting environment configurations.
📜 License
🤝 Contributing
We welcome contributions from the community! Please see CONTRIBUTING for details on how to get started.
🤖 Acknowledgments
This project was created in collaboration with ChatGPT (OpenAI), utilizing the GPT-4o, GPT-4.5, and GPT-3 models.
📅 Changelog
For detailed release notes, see CHANGELOG.
By clearly managing your environment variables and enabling dynamic configuration switching, dotenv-loader helps you streamline your deployment and development workflows, reduce errors, and maintain cleaner, more maintainable code.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dotenv_loader-1.0.2.tar.gz.
File metadata
- Download URL: dotenv_loader-1.0.2.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aacc1d1654899d43c69017561e4d87d1e76942fb690b0d9ddadb284598bfd6c2
|
|
| MD5 |
0e485f8aded3c0a98b2fde6688185356
|
|
| BLAKE2b-256 |
919e0b6526d4c9808dd78aa984dd80c5115ecbb1dde26f1ca1053b44e26d5111
|
Provenance
The following attestation bundles were made for dotenv_loader-1.0.2.tar.gz:
Publisher:
publish.yml on dbdeveloper/dotenv-loader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotenv_loader-1.0.2.tar.gz -
Subject digest:
aacc1d1654899d43c69017561e4d87d1e76942fb690b0d9ddadb284598bfd6c2 - Sigstore transparency entry: 251509019
- Sigstore integration time:
-
Permalink:
dbdeveloper/dotenv-loader@8c5e59e7acc7b37ae15f92d1d85c84b5b2ca0146 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/dbdeveloper
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8c5e59e7acc7b37ae15f92d1d85c84b5b2ca0146 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dotenv_loader-1.0.2-py3-none-any.whl.
File metadata
- Download URL: dotenv_loader-1.0.2-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf8defaafac275e529d11045c93ffa1ddd9e0deceed2a1333541a7afc63078a1
|
|
| MD5 |
aa47163617ada4e4d6c7d6e35677ef80
|
|
| BLAKE2b-256 |
2f7b63290b354aab8b83b0970e1f87727a0d0126c42235a21627ecea37afa969
|
Provenance
The following attestation bundles were made for dotenv_loader-1.0.2-py3-none-any.whl:
Publisher:
publish.yml on dbdeveloper/dotenv-loader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotenv_loader-1.0.2-py3-none-any.whl -
Subject digest:
cf8defaafac275e529d11045c93ffa1ddd9e0deceed2a1333541a7afc63078a1 - Sigstore transparency entry: 251509024
- Sigstore integration time:
-
Permalink:
dbdeveloper/dotenv-loader@8c5e59e7acc7b37ae15f92d1d85c84b5b2ca0146 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/dbdeveloper
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8c5e59e7acc7b37ae15f92d1d85c84b5b2ca0146 -
Trigger Event:
release
-
Statement type: