Configuration
Z8ter uses environment-based configuration with support for .env files, making it easy to manage settings across different environments.
Environment Files
Create a .env file in your project root:
# .env
DEBUG=true
SECRET_KEY=your-super-secret-key-change-in-production
# Database
DATABASE_URL=postgresql://user:pass@localhost/mydb
# Authentication
LOGIN_PATH=/login
APP_PATH=/app/dashboard
SESSION_TTL=2592000
# External Services
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASSWORD=secret
# Vite (development)
VITE_DEV_SERVER=http://localhost:5173
Loading Configuration
Using the Builder
from z8ter.builders.app_builder import AppBuilder
builder = AppBuilder()
builder.use_config(".env") # Load from .env file
# ...
app = builder.build(debug=True)
Accessing Configuration
Configuration is available as a service:
# In views or API endpoints
async def get(self, request: Request) -> Response:
config = request.app.state.services["config"]
# Get a value (raises KeyError if missing)
secret = config("SECRET_KEY")
# Get with default
debug = config("DEBUG", default=False)
# Cast to type
port = config("PORT", cast=int, default=8000)
debug = config("DEBUG", cast=bool, default=False)
Type Casting
The config function supports automatic type casting:
# String (default)
name = config("APP_NAME")
# Integer
port = config("PORT", cast=int)
# Boolean (accepts: true, 1, yes, on)
debug = config("DEBUG", cast=bool)
# Float
rate = config("TAX_RATE", cast=float)
# List (comma-separated)
from starlette.config import CommaSeparatedStrings
hosts = config("ALLOWED_HOSTS", cast=CommaSeparatedStrings)
# Custom cast function
def parse_json(value):
import json
return json.loads(value)
data = config("JSON_CONFIG", cast=parse_json)
Configuration Best Practices
1. Use Different Files per Environment
.env # Default/development
.env.production # Production overrides
.env.test # Test overrides
Load the appropriate file:
import os
env = os.getenv("APP_ENV", "development")
env_file = f".env.{env}" if env != "development" else ".env"
builder.use_config(env_file)
2. Never Commit Secrets
Add to .gitignore:
.env
.env.*
!.env.example
Create .env.example with placeholder values:
# .env.example - Copy to .env and fill in values
DEBUG=true
SECRET_KEY=change-me
DATABASE_URL=postgresql://user:pass@localhost/mydb
3. Validate Required Settings
# config/settings.py
from starlette.config import Config
config = Config(".env")
# Required settings (will raise if missing)
SECRET_KEY = config("SECRET_KEY")
DATABASE_URL = config("DATABASE_URL")
# Optional with defaults
DEBUG = config("DEBUG", cast=bool, default=False)
LOG_LEVEL = config("LOG_LEVEL", default="INFO")
4. Group Related Settings
# config/database.py
from starlette.config import Config
config = Config(".env")
DATABASE_URL = config("DATABASE_URL")
DATABASE_POOL_SIZE = config("DATABASE_POOL_SIZE", cast=int, default=5)
DATABASE_MAX_OVERFLOW = config("DATABASE_MAX_OVERFLOW", cast=int, default=10)
# config/auth.py
from starlette.config import Config
config = Config(".env")
SECRET_KEY = config("SECRET_KEY")
SESSION_TTL = config("SESSION_TTL", cast=int, default=86400 * 30)
LOGIN_PATH = config("LOGIN_PATH", default="/login")
APP_PATH = config("APP_PATH", default="/dashboard")
Common Configuration Options
Application Settings
# Application mode
DEBUG=true
APP_ENV=development
# Server
HOST=127.0.0.1
PORT=8000
# Security
SECRET_KEY=your-secret-key-at-least-32-chars
ALLOWED_HOSTS=localhost,127.0.0.1
Authentication Settings
# Session configuration
SESSION_TTL=2592000
SESSION_COOKIE_SECURE=true
SESSION_COOKIE_HTTPONLY=true
# Redirect paths
LOGIN_PATH=/login
APP_PATH=/app/dashboard
LOGOUT_REDIRECT=/
Database Settings
# PostgreSQL
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
# SQLite
DATABASE_URL=sqlite:///./data/app.db
# Connection pool
DATABASE_POOL_SIZE=5
DATABASE_MAX_OVERFLOW=10
DATABASE_POOL_TIMEOUT=30
Email Settings
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_USE_TLS=true
EMAIL_FROM=noreply@example.com
External APIs
# Stripe
STRIPE_PUBLIC_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
# AWS
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1
AWS_S3_BUCKET=my-bucket
Frontend/Vite
# Development server URL (enables HMR)
VITE_DEV_SERVER=http://localhost:5173
# Or leave empty for production mode
VITE_DEV_SERVER=
App Directory Configuration
Z8ter resolves the application root directory with this precedence:
- Explicit:
z8ter.set_app_dir("/path/to/app") - Environment:
Z8TER_APP_DIRenvironment variable - Default: Current working directory
import z8ter
# Explicitly set app directory
z8ter.set_app_dir("/var/www/myapp")
# Get current app directory
print(z8ter.get_app_dir())
# Access resolved paths
print(z8ter.BASE_DIR) # /var/www/myapp
print(z8ter.TEMPLATES_DIR) # /var/www/myapp/templates
print(z8ter.STATIC_PATH) # /var/www/myapp/static
Runtime Configuration
Accessing Config in Code
# endpoints/views/settings.py
from z8ter.endpoints.view import View
class Settings(View):
async def get(self, request: Request) -> Response:
config = request.app.state.services["config"]
return self.render(request, "pages/settings.jinja", {
"app_name": config("APP_NAME", default="My App"),
"debug_mode": config("DEBUG", cast=bool, default=False),
})
Using Config in Startup
# main.py
from z8ter.builders.app_builder import AppBuilder
builder = AppBuilder()
builder.use_config(".env")
# Access config before build
# Note: Config is available after use_config()
app = builder.build(debug=True)
# After build, access via app.state
config = app.state.services["config"]
print(f"Running in {'debug' if config('DEBUG', cast=bool) else 'production'} mode")
Environment-Specific Configuration
Development
# .env (development)
DEBUG=true
DATABASE_URL=sqlite:///./dev.db
VITE_DEV_SERVER=http://localhost:5173
LOG_LEVEL=DEBUG
Production
# .env.production
DEBUG=false
DATABASE_URL=postgresql://user:pass@prod-db:5432/app
VITE_DEV_SERVER=
LOG_LEVEL=WARNING
SESSION_COOKIE_SECURE=true
Testing
# .env.test
DEBUG=true
DATABASE_URL=sqlite:///:memory:
VITE_DEV_SERVER=
LOG_LEVEL=DEBUG
Configuration Patterns
Factory Pattern
# config/factory.py
import os
from starlette.config import Config
def get_config():
env = os.getenv("APP_ENV", "development")
if env == "production":
return Config(".env.production")
elif env == "test":
return Config(".env.test")
else:
return Config(".env")
Settings Class
# config/settings.py
from dataclasses import dataclass
from starlette.config import Config
@dataclass
class Settings:
debug: bool
secret_key: str
database_url: str
session_ttl: int
login_path: str
app_path: str
@classmethod
def from_env(cls, env_file: str = ".env") -> "Settings":
config = Config(env_file)
return cls(
debug=config("DEBUG", cast=bool, default=False),
secret_key=config("SECRET_KEY"),
database_url=config("DATABASE_URL"),
session_ttl=config("SESSION_TTL", cast=int, default=2592000),
login_path=config("LOGIN_PATH", default="/login"),
app_path=config("APP_PATH", default="/dashboard"),
)
# Usage
settings = Settings.from_env()
Next Steps
- CLI Reference - Command-line tools
- Getting Started - Quick start guide
- Authentication - Auth configuration