Skip to main content
DBOS Transact supports multiple database backends for both system state management and application data. This guide covers how to configure and use PostgreSQL, SQLite, and CockroachDB.

Supported Databases

DBOS supports two database types:
  • PostgreSQL - Recommended for production. Includes Amazon RDS, Azure Database for PostgreSQL, Google Cloud SQL, and CockroachDB
  • SQLite - Ideal for development and testing
DBOS uses two databases:
  1. System Database - Stores workflow state, recovery information, and internal metadata
  2. Application Database - Optional database for your application’s @DBOS.transaction() functions
These can be the same database or separate databases. Both must use the same database type (both PostgreSQL or both SQLite).

Quick Start

1

Choose Your Configuration

from dbos import DBOS, DBOSConfig

config = DBOSConfig(
    name="my-app",
    system_database_url="postgresql://user:password@localhost/myapp_dbos",
    application_database_url="postgresql://user:password@localhost/myapp"
)
DBOS(config=config)
2

Use Transactions

import sqlalchemy as sa

@DBOS.transaction()
def create_user(username: str, email: str) -> int:
    result = DBOS.sql_session.execute(
        sa.text(
            "INSERT INTO users (username, email) "
            "VALUES (:username, :email) RETURNING id"
        ),
        {"username": username, "email": email}
    ).fetchone()
    return result[0]

PostgreSQL

Connection String Format

postgresql://[user]:[password]@[host]:[port]/[database]?[parameters]
Components:
  • user - Database username (required)
  • password - Database password (required)
  • host - Database host (required)
  • port - Database port (optional, defaults to 5432)
  • database - Database name (required)
  • parameters - Additional connection parameters (optional)

Examples

config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://postgres:password@localhost/myapp"
)

System Database Configuration

DBOS automatically creates a system database when you provide an application database URL:
config = DBOSConfig(
    name="my-app",
    # Application database
    application_database_url="postgresql://user:pass@localhost/myapp",
    # System database automatically created as: myapp_dbos
)
Or specify both explicitly:
config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://user:pass@localhost/myapp",
    system_database_url="postgresql://user:pass@localhost/myapp_system"
)

Advanced PostgreSQL Configuration

Connection Pooling

config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://user:pass@localhost/myapp",
    db_engine_kwargs={
        "pool_size": 20,           # Connection pool size
        "max_overflow": 0,          # Additional connections when pool is full
        "pool_timeout": 30,         # Timeout waiting for connection
        "pool_pre_ping": True,      # Verify connections before using
    },
    sys_db_pool_size=10             # System database pool size
)

Custom Engine Parameters

config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://user:pass@localhost/myapp",
    db_engine_kwargs={
        "connect_args": {
            "application_name": "my-custom-app",
            "connect_timeout": 10,
            "options": "-c statement_timeout=30000"  # 30 second query timeout
        },
        "echo": True,  # Log all SQL statements (for debugging)
        "pool_pre_ping": True,
    }
)

SQLite

Connection String Format

sqlite:///[path/to/database.sqlite]

Examples

# Uses sqlite:///my_app.sqlite
config = DBOSConfig(name="my-app")

SQLite Features

Advantages:
  • Zero configuration for local development
  • No separate database server required
  • File-based, portable database
  • Perfect for testing and prototyping
Limitations:
  • Not suitable for production deployments
  • No concurrent writes from multiple processes
  • Limited scalability
SQLite is recommended for development and testing only. Use PostgreSQL for production deployments.

CockroachDB

CockroachDB is fully compatible with DBOS as it implements the PostgreSQL wire protocol.

Connection String

config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://user:password@cockroachdb-host:26257/myapp?sslmode=verify-full"
)

CockroachDB Cloud

config = DBOSConfig(
    name="my-app",
    application_database_url=(
        "postgresql://user:[email protected]:26257/myapp"
        "?sslmode=verify-full&sslrootcert=/path/to/ca.crt"
    )
)

Features

  • Distributed, resilient database
  • PostgreSQL compatibility
  • Horizontal scalability
  • Strong consistency guarantees
  • Built-in replication

Database Configuration Reference

DBOSConfig Parameters

name
str
required
Application name. Must be 3-30 characters, lowercase letters, numbers, dashes, and underscores only.
system_database_url
str
Connection string for DBOS system database. If not provided, defaults to:
  • SQLite: sqlite:///{name}.sqlite
  • PostgreSQL: {application_database_url}_dbos (if application DB is PostgreSQL)
application_database_url
str
Connection string for application database used in @DBOS.transaction() functions. Optional. If not provided, no application database is configured.
db_engine_kwargs
dict[str, Any]
SQLAlchemy engine parameters for application database. See SQLAlchemy documentation.Default values:
{
    "connect_args": {"application_name": "dbos_transact"},
    "pool_timeout": 30,
    "max_overflow": 0,
    "pool_size": 20,
    "pool_pre_ping": True,
}
sys_db_pool_size
int
Connection pool size specifically for system database. Overrides pool_size from db_engine_kwargs for system DB.

Environment Variables

You can use environment variables in connection strings:
import os

config = DBOSConfig(
    name="my-app",
    application_database_url=os.environ.get(
        "DATABASE_URL",
        "postgresql://localhost/myapp"
    )
)
Or in YAML configuration:
name: my-app
application_database_url: ${DATABASE_URL}
system_database_url: ${SYSTEM_DATABASE_URL}

Using the Application Database

Accessing the SQL Session

In @DBOS.transaction() functions, access the database via DBOS.sql_session:
import sqlalchemy as sa

@DBOS.transaction()
def get_user(user_id: int) -> dict:
    result = DBOS.sql_session.execute(
        sa.text("SELECT * FROM users WHERE id = :id"),
        {"id": user_id}
    ).fetchone()
    
    if not result:
        return None
    
    return {
        "id": result[0],
        "username": result[1],
        "email": result[2]
    }

SQLAlchemy ORM Support

DBOS works with SQLAlchemy ORM models:
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"
    
    id: Mapped[int] = mapped_column(primary_key=True)
    username: Mapped[str]
    email: Mapped[str]

@DBOS.transaction()
def create_user_orm(username: str, email: str) -> int:
    user = User(username=username, email=email)
    DBOS.sql_session.add(user)
    DBOS.sql_session.flush()
    return user.id

@DBOS.transaction()
def get_user_orm(user_id: int) -> User | None:
    return DBOS.sql_session.query(User).filter_by(id=user_id).first()

Read-Only Transactions

@DBOS.transaction(read_only=True)
def get_users_list() -> list[dict]:
    results = DBOS.sql_session.execute(
        sa.text("SELECT id, username FROM users")
    ).fetchall()
    
    return [{"id": r[0], "username": r[1]} for r in results]

Migrations

DBOS automatically manages system database schema migrations. For your application database, use standard migration tools:
pip install alembic
alembic init migrations
Configure alembic.ini with your database URL:
sqlalchemy.url = postgresql://user:password@localhost/myapp
Create and run migrations:
alembic revision --autogenerate -m "Create users table"
alembic upgrade head

DBOS CLI Migrations

You can also use DBOS’s built-in migration support:
from dbos import run_dbos_database_migrations

# Run migrations on startup
if __name__ == "__main__":
    run_dbos_database_migrations(["path/to/migrations"])
    DBOS.launch()

Schema Customization

By default, DBOS system tables use the dbos schema in PostgreSQL. You can customize this:
config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://localhost/myapp",
    dbos_system_schema="custom_schema"  # Use 'custom_schema' instead of 'dbos'
)
The dbos_system_schema setting cannot be changed after the system database is created. This requires a fresh database or manual migration.

Production Best Practices

1

Use PostgreSQL for Production

SQLite is not suitable for production. Use PostgreSQL, Amazon RDS, Azure Database for PostgreSQL, or CockroachDB.
2

Configure Connection Pooling

Set appropriate pool sizes based on your workload:
config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://...",
    db_engine_kwargs={"pool_size": 20, "max_overflow": 10},
    sys_db_pool_size=10
)
3

Enable Connection Health Checks

Use pool_pre_ping=True to verify connections before use:
db_engine_kwargs={"pool_pre_ping": True}
4

Set Timeouts

Configure connect and statement timeouts:
db_engine_kwargs={
    "connect_args": {
        "connect_timeout": 10,
        "options": "-c statement_timeout=30000"
    }
}
5

Use SSL/TLS

Enable SSL for database connections:
application_database_url="postgresql://user:pass@host/db?sslmode=require"
6

Separate System and Application Databases

For better isolation and performance:
config = DBOSConfig(
    name="my-app",
    application_database_url="postgresql://localhost/myapp",
    system_database_url="postgresql://localhost/myapp_system"
)

Troubleshooting

Connection Errors

Error: Database name must be specified in the connection URL Solution: Ensure your PostgreSQL URL includes a database name:
# ❌ Missing database name
"postgresql://user:pass@localhost"

# ✅ Correct
"postgresql://user:pass@localhost/myapp"

Pool Exhaustion

Error: QueuePool limit of size X overflow Y reached Solution: Increase pool size or reduce concurrent operations:
db_engine_kwargs={"pool_size": 30, "max_overflow": 20}

SQLite Concurrency Issues

Error: database is locked Solution: SQLite doesn’t support concurrent writes. Use PostgreSQL for concurrent workloads.

Next Steps

Build docs developers (and LLMs) love