Skip to main content

Ferrum

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.

Why Ferrum?

Existing Python ORMs often force developers to choose between:

  • Developer experience
  • Async support
  • Type safety
  • Performance

Ferrum aims to provide all four.

Goals

  • 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

Quick Example

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",
)

# Insert from an instance (sentinel PK is dropped so the DB default runs)
draft = User(id=0, email="dana@example.com")
created = await User.objects.create(conn, draft)

# Persist one instance's changes by primary key
created.is_active = False
await User.objects.update_instance(conn, created, fields=["is_active"])

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")

Features

Async First

No synchronous compatibility layer.

Ferrum is designed around modern async Python applications.

users = await User.objects.all(conn)

Pydantic Native

Models are built directly on top of Pydantic.

class User(Model):
    id: int
    email: str

No duplicate schema definitions.

Field Options

ferrum.Field() accepts column-level constraints that are carried through to DDL:

Parameter Type Description
db_default str | None DB-side DEFAULT expression (e.g. "NOW()", "''", "GEN_RANDOM_UUID()"). Token casing is normalised (now() → NOW()).
nullable bool | None Override annotation-derived nullability. Use nullable=False to force NOT NULL even on a T | None-annotated field.
db_index bool Emit a CREATE INDEX on this column (auto-named idx_{table}_{field}).
unique bool Emit a UNIQUE constraint.
db_column str | None Override the database column name.
primary_key bool Declare this field as the primary key.
uuid_generate "v4" | "v7" | None Set GEN_RANDOM_UUID() / UUIDV7() as the DB default for UUID PK columns.
max_length int | None Emit VARCHAR(n) instead of TEXT.
max_digits / decimal_places int | None Emit NUMERIC(p,s).
vector_dimensions int | None Required for Vector columns; emits VECTOR(n).
jsonb_list bool Store list[T] as JSONB instead of a PostgreSQL ARRAY.
generated bool Select/hydrate the DB-generated column, but exclude it from writes.
read_only bool Select/hydrate the column, but reject explicit write assignments.
from datetime import datetime
from typing import Annotated
from ferrum import Model, Field

class Event(Model):
    id: int
    # DB-side timestamp default; Python annotation allows None but column is NOT NULL
    created_at: Annotated[datetime | None, Field(db_default="now()", nullable=False)]
    # Indexed text column
    kind: Annotated[str, Field(db_index=True, max_length=64)]

makemigrations honours these field attributes:

  • db_default / nullable are written into CREATE TABLE and ADD COLUMN DDL.
  • db_index=True emits CREATE INDEX after the table op.
  • For already-existing tables, makemigrations now autodiffs index and column attribute changes against the state projected from prior migration files:
    • Adding db_index=True to an existing field → AddIndex op.
    • Removing db_index=True → DropIndex op.
    • Adding or changing db_default → AlterColumn … SET DEFAULT … op.
    • Removing db_default → AlterColumn … DROP DEFAULT op.
    • Changing nullability → AlterColumn … SET / DROP NOT NULL op (SET NOT NULL is classified destructive and requires --confirm).
    • Column type changes, renames, and drops remain manual (out of scope for v0.1).

Django-Inspired API

Familiar query interface.

users = await (
    User.objects
    .filter(email__contains="@gmail.com")
    .order_by("-created_at")
    .all(conn)
)

Typed aggregates and bounded PostgreSQL streaming use the same metadata allowlists and bound-parameter compiler path:

from ferrum.queryset import Aggregate

counts = await (
    Ticket.objects
    .group_by("team_id")
    .date_trunc("created_at", "day", alias="day")
    .having(total__gte=10)
    .aggregate(conn, total=Aggregate.count())
)

async with Ticket.objects.filter(active=True).stream(conn, chunk_size=500) as chunks:
    async for tickets in chunks:
        await process(tickets)

stream() preserves projection/deferred/value-queryset materialization and deterministically releases its cursor on exhaustion, early break, cancellation, or error. It rejects prefetch_related() because cross-chunk relationship batching is not safe. Filtered update_returning() provides atomic compare-and-set semantics: encode the expected state in filter() and treat an empty returned list as a lost race.

First-Class IDE Support

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.

Rust-Powered Core

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.

Cross-Driver Full-Text Search

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.

Architecture

┌──────────────────────────┐
│      Python API          │
│  Models / QuerySets      │
└────────────┬─────────────┘
             │
             ▼
┌──────────────────────────┐
│      Ferrum Core         │
│      (Rust Engine)       │
├──────────────────────────┤
│ Query Compiler           │
│ SQL AST                  │
│ Result Decoder           │
│ Migration Planner        │
└────────────┬─────────────┘
             │
             ▼
┌──────────────────────────┐
│       PostgreSQL         │
└──────────────────────────┘

Roadmap

v0.1 (complete)

  • 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)

v0.2 (in progress)

  • Upsert API (upsert, bulk_upsert with conflict targets and RETURNING)
  • Composite primary keys
  • Array field types (uuid[], text[], scalar arrays)
  • JSONB operators (__contains, __has_key)
  • RLS / tenant session helpers (set_config, tenant_session)
  • call_function for allowlisted stored-procedure calls
  • Migration ops for extensions, RLS policies, and function DDL
  • pgvector similarity score projection (vector_search helper)
  • Field(db_default=..., nullable=...) — first-class DB-side defaults and nullability override
  • makemigrations autodiff for index / default / nullability changes on existing tables
  • Typed aggregates, filtered UPDATE … RETURNING, and bounded QuerySet streaming
  • JSONB-list/generated/read-only metadata and read-only PostgreSQL schema drift reports
  • Query optimization (deferred fields, prefetch tuning)
  • Advanced relationship loading

v1.0

  • Production-ready stability
  • Performance benchmarking suite
  • Full documentation site

Project Status

Ferrum is currently in active development.

The API is not yet stable and breaking changes should be expected until the first public release.

Installation

# 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-orm

Bare 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.

Wire format (advanced)

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).

Examples

Runnable samples live under examples/:

Contributing

Contributions are welcome. Start with CONTRIBUTING.md for local setup, scoped verification, architecture rules, and pull request expectations.

License

Apache License 2.0

Metadata

Release files for ferrum-orm 0.1.17

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ferrum-orm 0.1.17
File Size Uploaded
ferrum_orm-0.1.17.tar.gz 197.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for ferrum-orm 0.1.17
File
ferrum_orm-0.1.17-cp311-abi3-manylinux_2_28_x86_64.whl CPython 3.11 abi3 Linux glibc 2.28+ x86-64 Details
ferrum_orm-0.1.17-cp311-abi3-manylinux_2_28_aarch64.whl CPython 3.11 abi3 Linux glibc 2.28+ ARM64 Details
ferrum_orm-0.1.17-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
ferrum_orm-0.1.17-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 3.7 MB

Release files / ferrum_orm-0.1.17.tar.gz

Download URL ferrum_orm-0.1.17.tar.gz
Size 197.7 kB
Tags Source
SHA-256 checksum
How to use checksums
1d91595194cad36abf1b2476af46e6909a6ed6ee0fd6f30c1f943e00ec6d88ce
BLAKE2b-256 checksum
How to use checksums
419ea3b1bd46dfa5837eaf9a3cc7fd94c67f4b15345318c0c0a6884dcf3996a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / ferrum_orm-0.1.17-cp311-abi3-manylinux_2_28_x86_64.whl

Download URL ferrum_orm-0.1.17-cp311-abi3-manylinux_2_28_x86_64.whl
Size 920.8 kB
Tags CPython 3.11 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
5b7e3e0386571d5369a55b807f267eb758c586c7c7fc9183d4a8b2534a6a6a1d
BLAKE2b-256 checksum
How to use checksums
d02e26e2ddb611765681eedb21b6aa6607ac0646ee9dfb64978902f5055cb108
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / ferrum_orm-0.1.17-cp311-abi3-manylinux_2_28_aarch64.whl

Download URL ferrum_orm-0.1.17-cp311-abi3-manylinux_2_28_aarch64.whl
Size 896.6 kB
Tags CPython 3.11 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
24bb960495b06d29f3c9371a55b52dea145de76cb6c72b23a1b91838fd36c0ed
BLAKE2b-256 checksum
How to use checksums
2743e68d83e27aeb72a87862dd430de211f68bfd5d793f481ce447f196d28bf4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / ferrum_orm-0.1.17-cp311-abi3-macosx_11_0_arm64.whl

Download URL ferrum_orm-0.1.17-cp311-abi3-macosx_11_0_arm64.whl
Size 841.0 kB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
a0fe33a3fdac12df87e7ce26ee73a2b70fb593044cd782fcb65fe6a9c0317447
BLAKE2b-256 checksum
How to use checksums
fbcae9cc372af29c8060b5ad21e8c0043b089a2cc097d7824255ec05e4aad9f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / ferrum_orm-0.1.17-cp311-abi3-macosx_10_12_x86_64.whl

Download URL ferrum_orm-0.1.17-cp311-abi3-macosx_10_12_x86_64.whl
Size 876.8 kB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
ad717bd6f6f33ccabdf069dfe1a2926aad0f1204dc0c12b86123e85edb19f714
BLAKE2b-256 checksum
How to use checksums
bb1f7f74351c79ee08b2c64d3b3c5d6f3e923574fa06777ab6eaf32023c25fd3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.17 This release

5 release files

0.1.15

5 release files

0.1.14

5 release files

0.1.13

5 release files

0.1.11

5 release files

0.1.9

5 release files

0.1.8

5 release files

0.1.7

5 release files

0.1.6

5 release files

0.1.5

5 release files

0.1.4

5 release files

0.1.3

5 release files

0.1.2

5 release files

0.1.1

5 release files

0.1.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page