Installation¶
This guide will help you install Edda and set up your development environment.
Prerequisites¶
- Python 3.11 or higher
- uv package manager (recommended) or pip
Installing Edda¶
Using uv¶
Install Edda from PyPI using uv:
This installs Edda with SQLite support, which is perfect for:
- Local development
- Testing
- Single-process deployments (suitable for development, testing, and low-traffic single-server apps)
Important: For multi-process or multi-pod deployments (K8s, Docker Compose with multiple replicas, etc.), you must use PostgreSQL or MySQL. SQLite supports multiple async workers within a single process, but its table-level locking makes it unsuitable for multi-process/multi-pod scenarios.
With database extras:
# With PostgreSQL support (recommended for production)
uv add edda-framework --extra postgresql
# With MySQL support
uv add edda-framework --extra mysql
# With Viewer UI (workflow visualization)
uv add edda-framework --extra viewer
# With PostgreSQL instant notifications (LISTEN/NOTIFY)
uv add edda-framework --extra postgres-notify
# All extras (PostgreSQL + MySQL + Viewer UI)
uv add edda-framework --extra postgresql --extra mysql --extra viewer
What gets installed:
- Base: SQLite support via
aiosqlite(always included) - postgresql:
asyncpgdriver for PostgreSQL - mysql:
aiomysqldriver for MySQL - viewer:
niceguiandhttpxfor workflow visualization UI - postgres-notify:
asyncpgdriver for PostgreSQL LISTEN/NOTIFY instant notifications
Using pip¶
If you prefer using pip:
# Basic installation
pip install edda-framework
# With PostgreSQL support
pip install "edda-framework[postgresql]"
# With MySQL support
pip install "edda-framework[mysql]"
# With Viewer UI
pip install "edda-framework[viewer]"
# With PostgreSQL instant notifications
pip install "edda-framework[postgres-notify]"
# All extras
pip install "edda-framework[postgresql,mysql,viewer]"
Installing from GitHub (Development Versions)¶
For testing the latest development version or a specific branch/commit, you can install directly from GitHub:
Latest Development Version¶
# Using uv
uv add git+https://github.com/i2y/edda.git
# Using pip
pip install git+https://github.com/i2y/edda.git
This installs the latest code from the main branch.
Specific Version, Branch, or Commit¶
# Specific tag (e.g., v0.1.0)
uv add git+https://github.com/i2y/edda.git@v0.1.0
pip install git+https://github.com/i2y/edda.git@v0.1.0
# Specific branch
uv add git+https://github.com/i2y/edda.git@feature-branch
pip install git+https://github.com/i2y/edda.git@feature-branch
# Specific commit
uv add git+https://github.com/i2y/edda.git@abc1234
pip install git+https://github.com/i2y/edda.git@abc1234
With Database Extras¶
# Using uv (PostgreSQL + Viewer)
uv add "git+https://github.com/i2y/edda.git[postgresql,viewer]"
# Using pip
pip install "git+https://github.com/i2y/edda.git[postgresql,viewer]"
When to use GitHub installation:
- ✅ Development & Testing: Try unreleased features or bug fixes
- ✅ Contributing: Test your changes before submitting a PR
- ✅ Specific Version: Pin to a particular commit or branch
- ❌ Production: Use PyPI releases for production deployments
Note: GitHub installations require Git to be installed on your system.
Verifying Installation¶
Check that Edda is installed correctly:
# test_installation.py
import asyncio
from edda import EddaApp, workflow, activity, WorkflowContext
@activity
async def hello_activity(ctx: WorkflowContext, name: str):
return f"Hello, {name}!"
@workflow
async def hello_workflow(ctx: WorkflowContext, name: str):
result = await hello_activity(ctx, name)
return {"message": result}
async def main():
# Create app with in-memory SQLite
app = EddaApp(service_name="demo-service", db_url="sqlite:///:memory:")
# Initialize the app before starting workflows
await app.initialize()
try:
# Start workflow
instance_id = await hello_workflow.start(name="World")
print(f"Workflow started: {instance_id}")
# Get result
instance = await app.storage.get_instance(instance_id)
result = instance['output_data']['result']
print(f"Result: {result}")
finally:
# Cleanup resources
await app.shutdown()
if __name__ == "__main__":
asyncio.run(main())
Run the test:
Expected output:
The result is extracted from instance['output_data']['result'], which contains the return value of the workflow.
Database Setup¶
Database Selection¶
| Database | Use Case | Multi-Worker Support | Production Ready |
|---|---|---|---|
| SQLite | Development, testing, single-process apps | ⚠️ Single-process only | ⚠️ Limited |
| PostgreSQL | Production, multi-process/multi-pod systems | ✅ Yes | ✅ Yes (Recommended) |
| MySQL | Production with existing MySQL infrastructure | ✅ Yes | ✅ Yes |
SQLite (Default)¶
No additional setup required! SQLite databases are created automatically:
from edda import EddaApp
# File-based SQLite (single-process only)
app = EddaApp(service_name="demo-service", db_url="sqlite:///workflow.db")
# In-memory (testing only)
app = EddaApp(service_name="demo-service", db_url="sqlite:///:memory:")
SQLite Considerations:
✅ Supported scenarios:
- Single-process deployments (even with multiple async workers within that process)
- Development and testing environments
- Low-traffic single-server applications
❌ Not supported:
- Multi-process deployments (Docker Compose with
replicas: 3, multiple systemd services) - Multi-pod deployments (Kubernetes with multiple replicas)
- High-concurrency production scenarios
⚠️ Performance limitations:
- Table-level locking (not row-level like PostgreSQL/MySQL)
- Concurrent writes are serialized, impacting throughput
- For production with multiple processes/pods, use PostgreSQL or MySQL
PostgreSQL¶
-
Install PostgreSQL (if not already installed)
-
Create a database:
- Configure connection:
from edda import EddaApp
app = EddaApp(
service_name="demo-service",
db_url="postgresql://user:password@localhost/edda_workflows"
)
Enabling Instant Notifications (LISTEN/NOTIFY)¶
For near-instant event and message delivery, enable PostgreSQL LISTEN/NOTIFY:
# Install the postgres-notify extra
uv add edda-framework --extra postgres-notify
# or
pip install "edda-framework[postgres-notify]"
from edda import EddaApp
app = EddaApp(
service_name="demo-service",
db_url="postgresql://user:password@localhost/edda_workflows",
use_listen_notify=True, # Enable LISTEN/NOTIFY (auto-detected by default)
notify_fallback_interval=30, # Fallback polling interval in seconds
)
Configuration options:
| Parameter | Type | Default | Description |
|---|---|---|---|
use_listen_notify |
bool \| None |
None |
None = auto-detect (enabled for PostgreSQL), True = force enable, False = force disable |
notify_fallback_interval |
int |
30 |
Fallback polling interval in seconds when NOTIFY is enabled |
Benefits:
- Near-instant event delivery (milliseconds vs. seconds with polling)
- Reduced database load (fewer polling queries)
- Automatic fallback to polling if NOTIFY fails
- Automatic reconnection on connection loss
See PostgreSQL LISTEN/NOTIFY for detailed documentation.
MySQL¶
-
Install MySQL (if not already installed)
-
Create a database:
- Configure connection:
from edda import EddaApp
app = EddaApp(
service_name="demo-service",
db_url="mysql://user:password@localhost/edda_workflows"
)
Schema Migration¶
Automatic Migration (Default)¶
Edda automatically applies database migrations at startup. No manual commands needed:
from edda import EddaApp
# Migrations are applied automatically at startup
app = EddaApp(
service_name="demo-service",
db_url="postgresql://user:pass@localhost/dbname"
)
Key features:
- Zero configuration: Works out of the box
- Multi-worker safe: Handles concurrent startup gracefully (race condition protected)
- dbmate compatible: Uses the same SQL files and
schema_migrationstable - Incremental: Only applies pending migrations
Manual Migration with dbmate (Optional)¶
For explicit schema control, you can disable auto-migration and use dbmate:
# Disable auto-migration
app = EddaApp(
service_name="demo-service",
db_url="postgresql://...",
auto_migrate=False # Use dbmate-managed schema
)
# Install dbmate
brew install dbmate # macOS
# Linux: curl -fsSL https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64 -o /usr/local/bin/dbmate && chmod +x /usr/local/bin/dbmate
# Add schema submodule to your project
git submodule add https://github.com/durax-io/schema.git schema
# Run migration manually
DATABASE_URL="postgresql://user:pass@localhost/dbname" dbmate -d ./schema/db/migrations/postgresql up
# Check status
dbmate -d ./schema/db/migrations/postgresql status
Note: Edda's auto-migration uses the same SQL files as dbmate, so you can switch between modes freely.
Multi-Worker Configuration¶
When running multiple Edda workers (e.g., in Kubernetes or with multiple processes), Edda automatically coordinates background tasks using leader election. Only one worker runs maintenance tasks (timers, message cleanup, etc.) while others focus on workflow execution.
from edda import EddaApp
app = EddaApp(
service_name="demo-service",
db_url="postgresql://...",
# Leader election settings (optional - defaults work well for most cases)
leader_heartbeat_interval=15, # How often workers check/renew leadership
leader_lease_duration=45, # How long before a failed leader is replaced
)
Configuration options:
| Parameter | Type | Default | Description |
|---|---|---|---|
leader_heartbeat_interval |
int |
15 |
Interval in seconds for leader heartbeat |
leader_lease_duration |
int |
45 |
Duration in seconds before leadership expires |
Notes:
- Default values work well for most deployments
- Reduce
leader_lease_durationfor faster failover (minimum: 3x heartbeat interval) - Leader election uses the database for coordination (no external dependencies)
Next Steps¶
- Quick Start: Build your first workflow in 5 minutes
- Core Concepts: Learn about workflows, activities, and durable execution
- Your First Workflow: Step-by-step tutorial