Database Configuration¶
Dazzle uses PostgreSQL as its database backend. PostgreSQL is required for both development and production.
Configuration¶
Environment Variable (Recommended)¶
CLI Flag¶
dazzle.toml¶
Configure the database URL in your project manifest:
[database]
url = "postgresql://user:password@localhost:5432/myapp"
# Or use env var indirection:
# url = "env:DATABASE_URL"
Docker Compose¶
When using dazzle serve (Docker mode), set the variable in your shell or a .env file:
URL Formats¶
DATABASE_URL |
Notes |
|---|---|
postgresql://user:pass@host:5432/db |
Standard format |
postgres://user:pass@host:5432/db |
Heroku-style, auto-converted to postgresql:// |
Local PostgreSQL Setup¶
Using Docker (Quickest)¶
docker run -d --name dazzle-postgres \
-e POSTGRES_USER=dazzle \
-e POSTGRES_PASSWORD=dazzle \
-e POSTGRES_DB=dazzle \
-p 5432:5432 \
postgres:16
export DATABASE_URL=postgresql://dazzle:dazzle@localhost:5432/dazzle
dazzle serve --local
Using Homebrew (macOS)¶
brew install postgresql@16
brew services start postgresql@16
createdb dazzle
export DATABASE_URL=postgresql://localhost:5432/dazzle
dazzle serve --local
Installing PostgreSQL Drivers¶
Install the postgres extra:
This installs psycopg[binary] (v3) and psycopg-pool.
Auth Database¶
Dazzle's authentication system can use a separate database via AUTH_DATABASE_URL. This is useful for shared auth across multiple Dazzle apps.
| Variable | Purpose | Default |
|---|---|---|
DATABASE_URL |
Application data | Required |
AUTH_DATABASE_URL |
Auth users and sessions | Falls back to DATABASE_URL |
export DATABASE_URL=postgresql://localhost:5432/myapp
export AUTH_DATABASE_URL=postgresql://localhost:5432/myapp_auth
dazzle serve --local
Connection Pool¶
Dazzle uses psycopg_pool.ConnectionPool for the main request-handler connections, and dedicated long-lived psycopg.AsyncConnection instances for the event framework. Both share the same DATABASE_URL.
Config¶
| Variable | Default | Description |
|---|---|---|
DAZZLE_DB_POOL_MIN |
2 |
Connections kept open even when idle |
DAZZLE_DB_POOL_MAX |
10 |
Hard ceiling on the main pool |
The event-framework connections (outbox publisher + consumer listeners) are not in the main pool — they're 1-3 additional long-lived connections per server process. Reserve headroom when sizing the pool against the Postgres server's max_connections.
Per-process connection count budget (rule of thumb):
DAZZLE_DB_POOL_MAX (main pool ceiling)
+ 2-3 (event framework: 1 outbox publisher + 1-2 listener consumers)
+ 1-2 (transient migration / schema-create on startup)
= ~14 connections per `dazzle serve` process
Multiply by WEB_CONCURRENCY (uvicorn workers) for total cluster footprint.
Local PostgreSQL¶
Default max_connections = 100 on a stock Postgres install is plenty for a single Dazzle dev server. No tuning needed.
If you run multiple example apps simultaneously (e.g. for cross-app testing), each gets its own database AND its own server process. With 5 example apps × 14 connections = 70 connections — still under 100. If you push into the limit, either:
- Lower
DAZZLE_DB_POOL_MAXper project (e.g.DAZZLE_DB_POOL_MAX=4) - Raise
max_connectionsinpostgresql.conf(requires server restart):max_connections = 200
Heroku Postgres¶
Heroku Postgres plans have per-tier connection ceilings — they're the dominant constraint for production deployments. Always set DAZZLE_DB_POOL_MAX * WEB_CONCURRENCY < plan_max_connections - 5 (the -5 leaves headroom for psql debug sessions, heroku pg:psql, and event-framework connections).
| Plan | max_connections |
Recommended DAZZLE_DB_POOL_MAX (with 4 workers) |
Notes |
|---|---|---|---|
| Essential-0 | 20 | 2 |
Tight — 2 × 4 = 8, plus 4 event-framework × 4 workers = 16; consider 1 worker only |
| Essential-1 | 40 | 5 |
5 × 4 = 20, + 16 event = 36; comfortable |
| Standard-0 | 120 | 15 |
15 × 4 = 60, + 16 event = 76; room to spare |
| Standard-2+ | 400+ | 25 |
Generous |
On the smallest Heroku plans, also consider WEB_CONCURRENCY=1 (single worker per dyno) and scale horizontally with heroku ps:scale web=N — that way each dyno's footprint is small and connection accounting is linear.
Heroku TCP timeouts¶
Heroku terminates idle TCP after 30 minutes of inactivity. The default psycopg_pool does not detect and reconnect — a queued idle connection picked up after 30 min will hit OperationalError: server closed the connection unexpectedly on the first query.
For production deployments, set pool_recycle (TBD — currently not exposed; if you hit this, file an issue referencing #1072 follow-ups).
Diagnostic commands¶
# Heroku
heroku pg:info # show current connection count + plan limit
heroku pg:psql -c "SELECT count(*) FROM pg_stat_activity WHERE datname = current_database();"
# Local
psql -d <dbname> -c "SELECT count(*) FROM pg_stat_activity WHERE datname = '<dbname>';"
psql -d <dbname> -c "SHOW max_connections;"
# Inspect idle-in-transaction sessions (the #1072 Bug A diagnostic)
psql -d <dbname> -c "SELECT pid, state, query FROM pg_stat_activity WHERE datname='<dbname>' AND state LIKE 'idle in transaction%';"
What pool-related symptoms look like¶
| Symptom | Likely cause | Fix |
|---|---|---|
psycopg_pool.PoolTimeout after ~30s |
Pool exhausted — too many concurrent in-flight requests | Increase DAZZLE_DB_POOL_MAX until error stops or you hit max_connections - 5 |
FATAL: too many clients already |
Cluster-wide ceiling hit | Lower DAZZLE_DB_POOL_MAX * WEB_CONCURRENCY * dyno_count below max_connections |
server closed the connection unexpectedly |
TCP idle-killed by Heroku / DBaaS provider | (See "Heroku TCP timeouts" above) |
CREATE INDEX ... waiting indefinitely |
A separate process holds idle in transaction on the table |
pg_terminate_backend(pid) the offender; root-cause the leak |
Schema Management¶
Dazzle automatically creates and migrates database tables on startup. No manual migration step is required for development.
- Schema changes: Adding entities or fields to your DSL and restarting the server applies the new schema. Dazzle uses
CREATE TABLE IF NOT EXISTSandALTER TABLE ADD COLUMNfor non-destructive migrations. - Production migrations: Use
dazzle dbcommands (Alembic) for controlled schema changes in production.
CI / Testing¶
To run the Dazzle test suite against PostgreSQL:
# Start a test database
docker run -d --name dazzle-test-pg \
-e POSTGRES_USER=dazzle \
-e POSTGRES_PASSWORD=dazzle_test \
-e POSTGRES_DB=dazzle_test \
-p 5432:5432 \
postgres:16
# Run tests
DATABASE_URL=postgresql://dazzle:dazzle_test@localhost:5432/dazzle_test \
pytest -m "not e2e" -x
The -x flag fails fast on the first error, which is useful for catching backend-specific issues.
The dsl_test run command tests a running server via HTTP and is backend-agnostic — it works with whatever database the server is configured to use.