Easily manage your application settings and secrets
Stela were the "information files" of ancient times. This library helps you manage your project settings and secrets with ease, using a simple and consistent approach.
Stela is a Python library that simplifies how you handle:
- Settings: Non-sensitive values that can be committed to your repository (API URLs, timeouts, etc.)
- Secrets: Sensitive values that should not be committed (passwords, tokens, etc.)
- Environment-specific configurations: Different values for development, testing, and production
- In a new project run
pip install stela
- On terminal, run
stela init --default --no-confirm
- Uncomment the
MY_SECRET
line in.env
- Add
from stela import env
and runprint(env.MY_SECRET)
in your code - Uncomment the
MY_SECRET
line in.env.local
and get the code again. - Add
export MY_SECRET=memory_value
in your terminal and get the code again.
New to multi-environment setups? Start with the Quick Setup guide: https://megalus.github.io/stela/quick_setup/
pip install stela
For detailed documentation, visit: https://megalus.github.io/stela/
- Learn once, use everywhere - Works with any Python project or framework
- Separate settings from secrets - Use multiple dotenv files to organize your configuration
- Environment-specific settings - Easily switch between development, testing, and production environments
-
Simple API - Access your settings with
from stela import env
- Extensible - Not limited to dotenv files, can load settings from any source (AWS Parameter Store, Vault, etc.)
Run the Stela initialization command to set up your project:
stela init --default
This creates four files:
-
.env
- Store your default settings (will be committed to git) -
.env.local
- Store your secrets (will be ignored by git) -
.stela
- Stela configuration file - Updates
.gitignore
to exclude sensitive files
Add your settings to .env
:
# .env - This file WILL be committed to your repository
# Store default settings and fake credentials here
API_URL="http://localhost:8000"
DB_URL="db://fake_user:fake_password@local_db:0000/name"
Add your real secrets to .env.local
:
# .env.local - This file will NOT be committed (ignored by git)
# Store real credentials and secrets here
DB_URL="db://real_user:real_password@real_db:0000/name"
Use the simple API to access your settings and secrets:
# my_script.py
from stela import env
# Access your settings with dot notation
API_URL = env.API_URL # http://localhost:8000
DATABASE_URL = env.DB_URL # db://real_user:real_password@real_db:0000/name
Stela automatically loads values from .env
first, then overrides them with values from .env.local
.
When the same key is defined in multiple places, Stela resolves it using this order (top wins):
- Value already present in the process environment (os.environ). Stela will not overwrite existing env vars.
- .env.{environment}.local
- .env.{environment}
- .env.local
- .env
If a key is missing everywhere, Stela raises a StelaValueError by default (configurable).
Stela makes it easy to manage different environments (development, testing, production):
Create a file for each environment:
# .env.development
API_URL="http://localhost:8000"
# .env.production
API_URL="https://api.example.com"
Set the STELA_ENV
environment variable to specify which environment to use:
# For development
export STELA_ENV=development
# For production
export STELA_ENV=production
Your code remains the same, but Stela will load the appropriate values:
from stela import env
# Will be "http://localhost:8000" when STELA_ENV=development
# Will be "https://api.example.com" when STELA_ENV=production
API_URL = env.API_URL
Stela isn't limited to dotenv files. You can load settings from any source:
Add a final loader in your .stela
configuration file:
# .stela
[stela]
final_loader = "path.to.my.final_loader"
# my_loaders.py
from typing import Any
from stela.config import StelaOptions
def final_loader(options: StelaOptions, env_data: dict[str, Any]) -> dict[str, Any]:
"""Load settings from a custom source and merge into env_data.
Args:
options: Stela configuration options (includes current_environment).
env_data: Data already loaded from dotenv files.
Returns:
Updated data dictionary.
"""
# Example: pretend we fetched data from an external source
external = {"API_TIMEOUT": "5", "FEATURE_FLAG": "true"}
# Merge/override values
env_data.update(external)
return env_data
from stela import env
# Values can come from dotenv files or your custom source
API_URL = env.API_URL
DB_PASSWORD = env.DB_PASSWORD
API_TIMEOUT = env.API_TIMEOUT # From custom loader
- Documentation: For detailed guides and examples, visit the documentation
- Issues: Found a bug? Have a question? Open an issue
- Contribute: Pull requests are welcome!