A Rust-backed async ORM for Python applications that use Pydantic models.
| Project | Status |
|---|---|
| CI | |
| Meta |
Ormdantic lets you declare database tables with Pydantic v2 models and run async CRUD, relationship loading, migrations, reflection, and native SQL execution through a Rust-backed runtime.
The project is designed for applications that want Python model ergonomics without giving up SQL database features. Python owns the model and API surface; Rust owns SQL compilation, type conversion, and driver execution.
| Area | What Ormdantic Provides |
|---|---|
| Models | Pydantic models decorated as database tables. |
| CRUD | Async insert, update, upsert, delete, find, count, and bulk update helpers. |
| Queries | Dictionary filters for ordinary cases and expression objects for advanced SQL. |
| Relationships | Explicit joined and select-in loaders, plus explicit relationship loading. |
| Transactions | Async transaction and session contexts. |
| Migrations | Snapshots, diffs, plans, migration artifacts, history, rollback, repair, and squash helpers. |
| Reflection | Live database inspection for tables, columns, indexes, constraints, schemas, views, sequences, and dialect metadata. |
| Drivers | SQLite, PostgreSQL, MySQL, MariaDB, SQL Server, and Oracle through the native runtime. |
uv add ormdanticfrom pydantic import BaseModel, Field
from ormdantic import Ormdantic
db = Ormdantic("sqlite:///app.sqlite3")
@db.table(pk="id", indexed=["name"])
class Flavor(BaseModel):
id: str
name: str = Field(min_length=2, max_length=63)
rating: int = 0
async def main() -> None:
await db.init()
await db[Flavor].insert(Flavor(id="vanilla", name="Vanilla", rating=5))
result = await db[Flavor].find_many(
{"rating": {"gte": 4}},
order_by=["name"],
)
for flavor in result.data:
print(flavor.name)Start with the documentation when you are new:
[Quick Start](https://ormdantic.yezz.me/quickstart/)walks through the first model, first table, first query, first session, and first migration preview.[learning Path](https://ormdantic.yezz.me/learning-path)tells new and advanced readers where to start.[Concepts](https://ormdantic.yezz.me/concepts/)explains tables, fields, relationships, querying, loading, sessions, migrations, events, and the native engine.[Supported Drivers](https://ormdantic.yezz.me/drivers/)explains SQLite, PostgreSQL, MySQL, MariaDB, SQL Server, and Oracle behavior.[Examples](https://ormdantic.yezz.me/examples/existing-databases/)contains task-focused how-to guides.[API Documentation](https://ormdantic.yezz.me/api/reference/)documents the Python API with generated references and usage notes.
Migration commands can read the database URL from --url, an exported
DATABASE_URL, or a local .env file:
export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
uv run ormdantic migrations init
uv run ormdantic migrations apply-dir migrations
uv run ormdantic migrations currentThe CLI prints redacted connection details and summaries such as
Applied 2 migrations from migrations. instead of only raw revision IDs.
Common commands:
bash scripts/lint.sh
bash scripts/test.sh
bash scripts/docs_build.shThe docs use Zensical:
uv run --group docs zensical build
uv run --group docs zensical serveRust crates live under rust/crates/ and are managed from the repository root Cargo.toml.
Ormdantic is evolving quickly. Prefer explicit migrations, review generated SQL before applying it in production, and check the driver-specific pages for dialect behavior.