Configuration
EVOID supports two config formats:
- TOML (
evoid.toml): traditional, human-readable - Python (
evoid_config.py): native, type-safe, IOP-native
Both produce the same config. Change infrastructure by changing config: business logic stays untouched.
Python Config (Recommended)
# evoid_config.py
from evoid.config import config
app = config(
service={"name": "my-api", "version": "1.0.0"},
runtime={"adapter": "asgi", "port": 8000},
engines={"storage": "memory", "cache": "memory"},
)
TOML Config
# evoid.toml
[service]
name = "my-api"
version = "1.0.0"
[runtime]
adapter = "asgi"
port = 8000
[engines]
storage = "memory"
cache = "memory"
Auto-Detection
EVOID auto-detects the config format:
from evoid.config import load_config
config = load_config() # Tries evoid.toml, then evoid_config.py
Project Structure
my-api/
evoid.toml # Project config (root)
shared/ # Shared code between services
services/
api/
evoid.toml # Service config (optional override)
main.py
workers/
evoid.toml # Service config for worker
main.py
Two levels of config:
- Project (
root/evoid.toml): defaults for all services - Service (
services/*/evoid.toml): overrides for one service
Service config merges into project config. Only specify what you want to override.
Complete Reference
[service] — Service Identity
[service]
name = "my-api"
version = "1.0.0"
| Field | Type | Default | Description |
|---|---|---|---|
name | str | "evoid-service" | Service name. Used in logs, metrics, and inter-service communication. |
version | str | "0.1.0" | Semantic version. Included in health check responses. |
[runtime] — Server Configuration
[runtime]
adapter = "asgi"
host = "0.0.0.0"
port = 8000
| Field | Type | Default | Description |
|---|---|---|---|
adapter | str | "asgi" | How Intents are triggered. See Adapter Reference. |
host | str | "0.0.0.0" | Bind address. Use 127.0.0.1 for local-only. |
port | int | 8000 | Bind port. |
[engines] — Infrastructure Selection
[engines]
schema = "native"
storage = "memory"
cache = "memory"
serializer = "json"
di = "native"
logger = "loguru"
metrics = "simple"
auth = "simple"
Each engine is pluggable. Change the value to swap the implementation.
| Field | Options | Default | Purpose |
|---|---|---|---|
schema | native, pydantic, msgspec, attrs | native | Data validation |
storage | memory, sqlite, sqlalchemy, redis, postgres, mongo | memory | Data persistence |
cache | memory, redis | memory | Caching layer |
serializer | json, msgspec, orjson | json | Serialization |
di | native | native | Dependency injection |
logger | structlog, loguru | loguru | Structured logging |
metrics | simple, prometheus | simple | Metrics collection |
auth | simple, jwt | simple | Authentication |
[pipeline] — Default Processors
[pipeline]
processors = ["validate", "authorize"]
| Field | Type | Default | Description |
|---|---|---|---|
processors | list[str] | ["validate", "authorize"] | Default processor chain for all Intents. Override per-Intent in code. |
Real-World Examples
Minimal API (Development)
[service]
name = "dev-api"
version = "0.1.0"
[runtime]
adapter = "asgi"
port = 8000
[engines]
schema = "native"
storage = "memory"
cache = "memory"
serializer = "json"
logger = "loguru"
Production API with PostgreSQL
[service]
name = "production-api"
version = "2.1.0"
[runtime]
adapter = "asgi"
host = "0.0.0.0"
port = 8000
[engines]
schema = "pydantic"
storage = "sqlalchemy"
cache = "redis"
serializer = "orjson"
logger = "structlog"
metrics = "prometheus"
auth = "jwt"
[pipeline]
processors = ["validate", "authorize", "audit"]
evo sync
# Installs: pydantic, sqlalchemy, aiosqlite, redis, orjson, structlog, prometheus-client, pyjwt
Telegram Bot
[service]
name = "my-bot"
version = "1.0.0"
[runtime]
adapter = "telegram"
[engines]
schema = "native"
storage = "sqlite"
cache = "memory"
serializer = "json"
logger = "loguru"
Microservices (Multiple Services)
Project root (evoid.toml):
[service]
name = "my-platform"
version = "1.0.0"
[engines]
schema = "pydantic"
storage = "sqlalchemy"
cache = "redis"
serializer = "json"
logger = "structlog"
API service (services/api/evoid.toml):
[service]
name = "api"
[runtime]
adapter = "asgi"
port = 8000
Worker service (services/workers/evoid.toml):
[service]
name = "workers"
[runtime]
adapter = "cli"
[engines]
storage = "sqlite"
The worker inherits schema, cache, serializer, logger from project config but overrides storage and adapter.
Config Precedence
Service config → merges into → Project config → defaults
- Start with project config defaults
- Service config overrides specific fields
- Environment variables override both (if supported)
Example:
# Project: services/ with SQLite
[engines]
storage = "sqlite"
# Service: services/cache-only/evoid.toml
# This service only needs memory — override storage
[engines]
storage = "memory"
Adapter Reference
| Adapter | Use Case | Package Required | Trigger Source |
|---|---|---|---|
asgi | HTTP APIs | evoid[asgi] | HTTP requests |
cli | Command-line tools | core only | Terminal commands |
telegram | Telegram bots | evoid[telegram] | Telegram messages |
robyn | Robyn framework | evoid[robyn] | HTTP requests |
websocket | WebSocket apps | evoid[asgi] | WebSocket messages |
Syncing Dependencies
evo sync reads evoid.toml, maps engine names to packages, and installs them:
evo sync
# Reads: evoid.toml
# Maps: storage="sqlalchemy" → sqlalchemy[asyncio], aiosqlite
# Installs via: uv add
Engine → Package Map
| Engine | Value | Packages Installed | Built-in? |
|---|---|---|---|
schema | native | none | ✓ |
schema | pydantic | pydantic>=2.0.0 | extra |
schema | msgspec | msgspec>=0.18.0 | extra |
storage | memory | none | ✓ |
storage | sqlite | aiosqlite>=0.20.0 | extra |
storage | sqlalchemy | sqlalchemy[asyncio]>=2.0.0, aiosqlite | extra |
storage | redis | redis>=4.0.0 | plugin |
storage | postgres | asyncpg>=0.28.0 | plugin |
cache | memory | none | ✓ |
cache | redis | redis>=4.0.0 | plugin |
serializer | json | none | ✓ |
serializer | msgspec | msgspec>=0.18.0 | extra |
serializer | orjson | orjson>=3.9.0 | extra |
logger | structlog | structlog>=24.0.0 | extra |
logger | loguru | loguru>=0.7.0 | extra |
metrics | simple | none | ✓ |
metrics | prometheus | prometheus-client>=0.15.0 | extra |
auth | simple | none | ✓ |
auth | jwt | pyjwt>=2.10.0 | extra |
adapter | asgi | starlette>=0.27.0, uvicorn[standard]>=0.24.0 | extra |
adapter | robyn | robyn>=0.30.0 | extra |
adapter | telegram | aiogram>=3.0.0 | extra |
Optional Dependencies
Install only what you need. Core EVOID has minimal required dependencies:
# Core extras (built into EVOID)
uv add "evoid[asgi]" # HTTP APIs
uv add "evoid[pydantic]" # Pydantic schemas
uv add "evoid[sqlite]" # SQLite storage
uv add "evoid[loguru]" # Loguru logging
uv add "evoid[full]" # All extras
# Plugins (separate packages)
uv add evoid-redis # Redis cache
uv add evoid-postgresql # PostgreSQL storage
uv add evoid-di # Advanced DI
uv add evoid-auth # Custom auth providers
Environment Variables
Override config values at runtime:
EVOID_HOST=127.0.0.1
EVOID_PORT=3000
EVOID_ADAPTER=cli
Related
- Installation: Install EVOID
- Plugins: Custom engines
- Architecture: How config affects execution