Skip to content

Automatic Configuration

Zenith automatically configures your application based on the environment, eliminating boilerplate setup code. This example demonstrates the framework’s automatic configuration and enhanced database models.

from zenith import Zenith
# Zenith automatically configures everything
app = Zenith()
# This single line provides:
# - Environment detection (development/production)
# - Database configuration (SQLite for dev, DATABASE_URL for prod)
# - CORS settings (permissive for dev, secure for prod)
# - Security headers (appropriate for environment)
# - Error handling (detailed for dev, secure for prod)
# - Request logging (debug for dev, structured for prod)
# - Hot reload in development
# - And more...

When you create a Zenith application, it automatically:

In Development:

  • Uses SQLite database (no setup required)
  • Enables permissive CORS for frontend development
  • Provides detailed error messages
  • Adds debug toolbar
  • Enables hot reload
  • Uses development secret key

In Production:

  • Requires DATABASE_URL environment variable
  • Configures secure CORS from ALLOWED_ORIGINS
  • Returns safe error messages
  • Adds security headers
  • Requires SECRET_KEY environment variable
  • Enables structured logging

Zenith provides ZenithModel - an enhanced SQLModel base class with built-in query methods:

from zenith.db import ZenithModel
from sqlmodel import Field
from datetime import datetime
class User(ZenithModel, table=True):
id: int | None = Field(primary_key=True)
name: str = Field(max_length=100)
email: str = Field(unique=True)
active: bool = Field(default=True)
created_at: datetime = Field(default_factory=datetime.now)

ZenithModel provides intuitive query methods:

# Get all users
users = await User.all()
# Find by ID
user = await User.find(1) # Returns None if not found
user = await User.find_or_404(1) # Raises 404 if not found
# Create new user
user = await User.create(
name="Alice",
email="alice@example.com"
)
# Chainable queries
active_users = await (
User.where(active=True)
.order_by('-created_at') # '-' prefix for descending
.limit(10)
.all()
)
# With relationships
posts = await (
Post.where(published=True)
.includes('author') # Eager load relationships
.order_by('-created_at')
.limit(20)
.all()
)

ZenithModel automatically uses the request-scoped database session:

@app.get("/users")
async def get_users():
# No need to inject or manage database sessions
users = await User.where(active=True).all()
return {
"users": [u.model_dump() for u in users],
"count": len(users)
}
@app.post("/users")
async def create_user(name: str, email: str):
# Create, save, and return in one operation
user = await User.create(name=name, email=email)
return {"user": user.model_dump()}
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# Automatic 404 handling
user = await User.find_or_404(user_id)
return {"user": user.model_dump()}

Every ZenithModel inherits Pydantic’s model_dump() method for JSON serialization:

@app.get("/api/users")
async def api_users():
users = await User.all()
return {
"users": [user.model_dump() for user in users],
"total": len(users)
}

Zenith adapts to your environment automatically:

from zenith import Zenith
# Development (auto-detected)
app = Zenith() # Uses SQLite, debug mode, permissive CORS
# Production (auto-detected via environment variables)
app = Zenith() # Uses DATABASE_URL, secure settings, production middleware

Zenith respects these environment variables:

Terminal window
# Required in production
DATABASE_URL=postgresql://user:pass@host/db
SECRET_KEY=your-secure-secret-key
ALLOWED_ORIGINS=https://yourdomain.com,https://api.yourdomain.com
# Optional
DEBUG=false # Force production mode
CORS_MAX_AGE=3600 # CORS cache duration
LOG_LEVEL=INFO # Logging level
examples/03-modern-developer-experience.py
from zenith import Zenith
from zenith.db import ZenithModel
from sqlmodel import Field
from datetime import datetime
from typing import Optional
# Zero configuration needed
app = Zenith()
# Define your models
class User(ZenithModel, table=True):
id: Optional[int] = Field(primary_key=True)
name: str
email: str = Field(unique=True)
active: bool = Field(default=True)
created_at: datetime = Field(default_factory=datetime.now)
class Post(ZenithModel, table=True):
id: Optional[int] = Field(primary_key=True)
title: str
content: str
published: bool = Field(default=False)
user_id: int = Field(foreign_key="user.id")
created_at: datetime = Field(default_factory=datetime.now)
@app.on_event("startup")
async def startup():
# Create tables if they don't exist
await app.database.create_all()
@app.get("/")
async def home():
"""Show auto-configured features."""
return {
"message": "Zenith is running with automatic configuration",
"environment": "development" if app.debug else "production",
"features": {
"database": "Connected and ready",
"cors": "Configured for your environment",
"security": "Headers and middleware active",
"sessions": "Request-scoped and automatic",
"serialization": "JSON handling optimized"
}
}
@app.get("/users")
async def list_users(active: bool = True, limit: int = 10):
"""List users with filtering."""
users = await (
User.where(active=active)
.order_by('-created_at')
.limit(limit)
.all()
)
return {
"users": [u.model_dump() for u in users],
"total": len(users),
"filters": {"active": active, "limit": limit}
}
@app.post("/users")
async def create_user(name: str, email: str):
"""Create a new user."""
user = await User.create(name=name, email=email)
return {
"message": "User created successfully",
"user": user.model_dump()
}
@app.get("/users/{user_id}")
async def get_user(user_id: int):
"""Get user by ID."""
user = await User.find_or_404(user_id)
return {"user": user.model_dump()}
@app.post("/users/{user_id}/posts")
async def create_post(user_id: int, title: str, content: str):
"""Create a post for a user."""
# Verify user exists
user = await User.find_or_404(user_id)
# Create post
post = await Post.create(
title=title,
content=content,
user_id=user.id
)
return {
"message": "Post created",
"post": post.model_dump()
}
@app.get("/posts")
async def list_posts():
"""List published posts."""
posts = await (
Post.where(published=True)
.order_by('-created_at')
.limit(20)
.all()
)
return {
"posts": [p.model_dump() for p in posts],
"count": len(posts)
}
if __name__ == "__main__":
import uvicorn
print("🚀 Zenith Modern DX Demo")
print("✨ Everything is auto-configured!")
print("📊 Visit http://localhost:8003/")
uvicorn.run(app, host="0.0.0.0", port=8003)
  • Start coding immediately without setup
  • Automatic database configuration
  • Built-in development tools
  • Intuitive query methods
  • Automatic session management
  • Clean, readable API
  • Environment-aware configuration
  • Security headers included
  • Performance optimizations
  • Full type hints throughout
  • IDE autocomplete support
  • Runtime validation

Zenith’s automatic configuration and enhanced models let you focus on building your application instead of configuring it. The framework handles the complexity while providing escape hatches when you need them.