A next-generation async ORM for Python. Rust-powered engine. Pydantic-native models. Django-inspired developer experience.
Ferrum is an async-first ORM designed for modern Python applications.
Built around a Rust-powered core and a Python-native API, Ferrum combines the ergonomics of Django's ORM, the type safety of Pydantic, and the performance of Rust.
Existing Python ORMs often force developers to choose between:
- Developer experience
- Async support
- Type safety
- Performance
Ferrum aims to provide all four.
- Native async from day one
- Pydantic-first models
- Django-inspired ORM experience
- Rust-powered query engine
- PostgreSQL-first architecture (MySQL, SQLite, and SQL Server via optional extras)
- Type-safe query construction
- Automatic migrations
- High-performance result hydration
- Production-ready observability
from ferrum import Model
class User(Model):
id: int
email: str
is_active: bool = True
user = await User.objects.create(
conn,
email="john@example.com",
)
users = await (
User.objects
.filter(is_active=True)
.order_by("-id")
.limit(10)
.all(conn)
)
async with conn.transaction() as tx:
user = await User.objects.create(tx, email="jane@example.com")
await AuditLog.objects.create(tx, user_id=user.id, action="signup")No synchronous compatibility layer.
Ferrum is designed around modern async Python applications.
users = await User.objects.all(conn)Models are built directly on top of Pydantic.
class User(Model):
id: int
email: strNo duplicate schema definitions.
Familiar query interface.
users = await (
User.objects
.filter(email__contains="@gmail.com")
.order_by("-created_at")
.all(conn)
)Ferrum ships a PEP 561 py.typed marker, so editors and type checkers (mypy, pyright,
ty) resolve its inline hints out of the box. Model.objects is typed as
QuerySet[YourModel], chaining preserves the model type, and terminals infer precise results —
no casts:
users: list[User] = await User.objects.filter(is_active=True).all(conn) # list[User]
user: User | None = await User.objects.first(conn) # User | None
rows: list[dict[str, Any]] = await User.objects.values("id", "email").all(conn)
ids: list[Any] = await User.objects.values_list("id", flat=True).all(conn)values() / values_list() return dedicated ValuesQuerySet, ValuesListQuerySet, and
FlatValuesListQuerySet variants (all exported from ferrum) so all() returns
list[dict[str, Any]], list[tuple[Any, ...]], or list[Any] respectively.
Performance-critical components are implemented in Rust:
- Query compilation
- SQL generation
- Result decoding
- Schema analysis
- Migration planning
This allows Ferrum to maintain a Pythonic API without sacrificing performance.
Native full-text search across PostgreSQL, MySQL, SQLite FTS5, and SQL Server — one QuerySet API, dialect-specific SQL emit and migration DDL.
Query modes (filter lookups and ranking):
| Mode | Lookup operator | Typical use |
|---|---|---|
plain |
__match |
Natural-language terms |
phrase |
__match_phrase |
Exact phrase |
websearch |
__match_websearch |
Web-style quotes, - negation |
boolean |
__match_boolean |
Boolean operators (&, |, !) |
Convenience methods:
# Filter + relevance ranking in one call
hits = await Article.objects.search(
"python async orm", field="body", mode="websearch"
).limit(10).all(conn)
# Rank without an implicit filter
ranked = await Article.objects.rank_by("body", "rust", mode="plain").all(conn)Index declaration — PostgreSQL uses TSVector columns; other drivers index base
text columns via Meta.full_text_indexes:
from ferrum.models import Field, FullTextIndex
class Article(Model):
search_vector: Annotated[TSVector, Field(fts_config="english")] | None = None
body: str = ""
class Meta:
full_text_indexes = [FullTextIndex(fields=("body",), config="english")]Query strings are always bound parameters; fts_config and index names come from
model-metadata allowlists only. See Getting Started → Vector and full-text columns
and API Reference for per-dialect DDL and operator mapping.
┌──────────────────────────┐
│ Python API │
│ Models / QuerySets │
└────────────┬─────────────┘
│
▼
┌──────────────────────────┐
│ Ferrum Core │
│ (Rust Engine) │
├──────────────────────────┤
│ Query Compiler │
│ SQL AST │
│ Result Decoder │
│ Migration Planner │
└────────────┬─────────────┘
│
▼
┌──────────────────────────┐
│ PostgreSQL │
└──────────────────────────┘
- PostgreSQL support
- Basic CRUD operations
- Async query execution
- Pydantic models
- Query builder
- Type-safe filters
- Transactions and savepoints
- Bulk operations (
bulk_create,bulk_update,bulk_delete) - Migrations (schema diff, apply, revert, CLI)
- Relationships (ForeignKey, OneToOne, ManyToMany)
- pgvector KNN search and HNSW/IVFFLAT index DDL
- Full-text search (cross-dialect: PostgreSQL, MySQL, SQLite FTS5, SQL Server)
- Observability hooks (Tier A/B/C)
- CLI (
makemigrations,migrate,revert,showmigrations,inspectdb,resetdb)
- Upsert API (
upsert,bulk_upsertwith conflict targets andRETURNING) - Composite primary keys
- Array field types (
uuid[],text[], scalar arrays) - JSONB operators (
__contains,__has_key) - RLS / tenant session helpers (
set_config,tenant_session) -
call_functionfor allowlisted stored-procedure calls - Migration ops for extensions, RLS policies, and function DDL
- pgvector similarity score projection (
vector_searchhelper) - Query optimization (deferred fields, prefetch tuning)
- Advanced relationship loading
- Production-ready stability
- Performance benchmarking suite
- Full documentation site
Ferrum is currently in active development.
The API is not yet stable and breaking changes should be expected until the first public release.
# PostgreSQL (most common)
pip install 'ferrum-orm[pg]'
# PostgreSQL + migrations CLI
pip install 'ferrum-orm[pg,cli]'
# MySQL
pip install 'ferrum-orm[mysql]'
# SQLite + migrations CLI (testing / local dev)
pip install 'ferrum-orm[sqlite,cli]'
# SQL Server (also needs a system ODBC driver, e.g. msodbcsql18)
pip install 'ferrum-orm[mssql]'
# Optional MessagePack wire format for the Python<->Rust boundary
pip install 'ferrum-orm[msgpack]'
# Everything (all drivers + CLI + dotenv)
pip install 'ferrum-orm[all]'
# Core ORM only (no database driver — install a driver extra before connecting)
pip install ferrum-ormBare ferrum-orm installs Pydantic and the Rust core only. Choose a driver extra
(pg, mysql, sqlite, or mssql) before calling ferrum.connect().
MySQL, SQLite, and SQL Server are thin-parity backends: they support core CRUD
and migrations but not transactions, upsert, bulk_update, RLS, or pgvector
(PostgreSQL only). SQL Server connects via aioodbc/pyodbc and requires a system
ODBC driver such as msodbcsql18; DSNs use the mssql:// or sqlserver:// scheme.
The Python↔Rust IR/hydration boundary defaults to JSON. Installing the msgpack
extra lets you switch it to MessagePack, selected via the FERRUM_WIRE_FORMAT
environment variable (json | msgpack) or the [ferrum] wire_format key in
ferrum.toml / pyproject.toml. JSON remains the default; MessagePack is opt-in.
From source, build the native extension with maturin develop (or mise run dev).
Runnable samples live under examples/:
examples/simple/— async CRUD script (no web framework)examples/migrations/— CLI, plan generation, apply, and forward fix-upsexamples/fastapi_quickstart/— FastAPI integration
Contributions are welcome. Start with CONTRIBUTING.md for local setup,
scoped verification, architecture rules, and pull request expectations.
Apache License 2.0