https://github.com/vsdudakov/yara-orm
Fast async Python ORM with a Rust engine β Tortoise-style models, querysets, relations and migrations for PostgreSQL, MySQL and SQLite. A faster, fully-typed alternative to Tortoise ORM and async SQLAlchemy.
https://github.com/vsdudakov/yara-orm
async async-orm asyncio data-mapper database database-orm high-performance mariadb migrations mysql orm postgresql pyo3 python python-orm query-builder rust sqlalchemy sqlite tortoise-orm
Last synced: about 16 hours ago
JSON representation
Fast async Python ORM with a Rust engine β Tortoise-style models, querysets, relations and migrations for PostgreSQL, MySQL and SQLite. A faster, fully-typed alternative to Tortoise ORM and async SQLAlchemy.
- Host: GitHub
- URL: https://github.com/vsdudakov/yara-orm
- Owner: vsdudakov
- License: mit
- Created: 2026-06-28T17:56:04.000Z (7 days ago)
- Default Branch: main
- Last Pushed: 2026-07-03T20:42:01.000Z (1 day ago)
- Last Synced: 2026-07-03T21:37:56.665Z (1 day ago)
- Topics: async, async-orm, asyncio, data-mapper, database, database-orm, high-performance, mariadb, migrations, mysql, orm, postgresql, pyo3, python, python-orm, query-builder, rust, sqlalchemy, sqlite, tortoise-orm
- Language: Python
- Homepage: https://pypi.org/project/yara-orm/
- Size: 1.76 MB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: docs/contributing.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Yara ORM
**A fast, async Python ORM with a Rust engine β [Tortoise](https://tortoise.github.io/)-style
models, querysets, relations and migrations for PostgreSQL, MySQL and SQLite.**
[](https://github.com/vsdudakov/yara-orm/actions/workflows/ci.yml)
[](https://pypi.org/project/yara-orm/)
[](https://github.com/vsdudakov/yara-orm)
[](#development)
[](https://vsdudakov.github.io/yara-orm/)
[](LICENSE.md)
[](https://github.com/sponsors/vsdudakov)
π **Documentation: [vsdudakov.github.io/yara-orm](https://vsdudakov.github.io/yara-orm/)**
βοΈ **Deep dive: [How the GIL, PyO3 & asyncio cooperate](https://dev.to/vsdudakov/i-built-a-python-orm-with-a-rust-engine-heres-how-the-gil-pyo3-and-asyncio-actually-cooperate-4fkj)** β how the Rust engine bridges Python's event loop without the GIL collapsing it.
Yara ORM is a high-performance **async ORM for Python** that pairs the ergonomics
of a Django/Tortoise-style API β models, querysets, relations, aggregation and
migrations β with a hot path (connection pooling, parameter binding, row decoding)
written in compiled **Rust** (PyO3 + tokio). It is a drop-in-feel **alternative to
Tortoise ORM and async SQLAlchemy**: **2β9Γ faster** than popular pure-Python ORMs
on common operations, with first-class **PostgreSQL**, **MySQL** and **SQLite** backends, full
type hints, and **100% test coverage**.
```python
from yara_orm import Model, YaraOrm, fields
class User(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=120)
await YaraOrm.init("postgres://localhost/app")
await YaraOrm.generate_schemas()
await User.create(name="Ada")
print(await User.filter(name__icontains="ad").count())
```
---
## Highlights
- β‘ **Rust engine** β pooling, binding and decoding in compiled code; the async
bridge (PyO3 + tokio) keeps your event loop free.
- π§© **Familiar API** β Tortoise/Django-style models, lazy chainable querysets,
`Q` objects, aggregation, `prefetch_related`, transactions, signals. Coming from
Tortoise? Most code moves across unchanged β see
[Migrating from Tortoise ORM](https://vsdudakov.github.io/yara-orm/guides/migrating-from-tortoise/).
- ποΈ **Pluggable backends** β PostgreSQL, MySQL/MariaDB and SQLite today, selected by
URL; a new database is one Rust trait + one Python dialect.
- π **Migrations** β operation-based, auto-generated, backend-portable
(`makemigrations` / `upgrade` / `downgrade`).
- π§ͺ **Quality** β fully typed, linted (ruff + ty) and **100% test coverage**.
## Installation
```bash
pip install yara-orm
```
Prebuilt wheels are published for Linux, macOS and Windows on CPython 3.9β3.14,
so installation needs **no Rust toolchain**. (Installing the source
distribution on an unsupported platform compiles the engine and requires a Rust
toolchain β see [Development](#development).)
## Quick start
```python
import asyncio
from yara_orm import Model, YaraOrm, fields
class Tournament(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=100)
created_at = fields.DatetimeField(auto_now_add=True)
class Event(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=100, index=True)
tournament = fields.ForeignKeyField("Tournament", related_name="events")
async def main() -> None:
await YaraOrm.init("postgres://localhost/app") # or "mysql://β¦", "sqlite:///app.db"
await YaraOrm.generate_schemas()
cup = await Tournament.create(name="World Cup")
await Event.create(name="Final", tournament=cup)
# Lazy, chainable queries
finals = await Event.filter(name__icontains="fin").order_by("-id")
count = await Event.filter(tournament=cup).count()
# Relations
async for event in cup.events:
print(event.name, "β", (await event.tournament).name)
await YaraOrm.close()
asyncio.run(main())
```
## Querying
```python
# Lookups: exact, not, gt/gte/lt/lte, in, isnull, contains/icontains,
# startswith/endswith (+ case-insensitive `i` variants)
await User.filter(age__gte=18, name__icontains="a").order_by("-age").limit(10)
# Complex boolean filters with Q
from yara_orm import Q
await User.filter(Q(name="Ada") | Q(age__lt=30)).exclude(active=False)
# Aggregation + group by
from yara_orm import Count, Sum
await Author.annotate(books=Count("books")).filter(books__gte=1)
await Book.annotate(total=Sum("rating")).group_by("author_id").values("author_id", "total")
# Construction-free projections
await User.all().values("id", "name")
await User.all().values_list("name", flat=True)
```
Model methods: `create`, `bulk_create`, `get`, `get_or_none`, `filter`,
`exclude`, `all`, `annotate`, `prefetch_related`, `raw`; instances `save`,
`delete`, `fetch_related`.
## Relations
```python
class Author(Model):
name = fields.CharField(max_length=100)
class Book(Model):
title = fields.CharField(max_length=200)
author = fields.ForeignKeyField("Author", related_name="books")
tags = fields.ManyToManyField("Tag", related_name="books")
book = await Book.create(title="Compilers", author=author)
await book.tags.add(tag1, tag2) # m2m add / remove / clear
await book.author # forward FK (awaitable)
async for b in author.books: ... # reverse manager
await Author.all().prefetch_related("books") # no N+1
```
`ForeignKeyField`, `OneToOneField`, `ManyToManyField`, recursive self-FK,
`related_name`, `Prefetch(rel, queryset=...)`.
## Transactions, signals & more
```python
from yara_orm import in_transaction, atomic, pre_save, connections
async with in_transaction(): # commit on success, rollback on error
await Account.create(name="A")
async with in_transaction(): # nesting opens a savepoint
await Account.create(name="B") # rolls back independently on error
@atomic(isolation="SERIALIZABLE") # isolation levels (PostgreSQL/MySQL)
async def transfer(): ...
@pre_save(User) # lifecycle signals
async def on_save(sender, instance, using_db, update_fields): ...
await connections.get("default").execute("INSERT ...", [..]) # manual SQL
```
Also: **enum fields** (`IntEnumField`/`CharEnumField`), column/table
**comments** (`description=`, `Meta.table_description`), and **multi-database
routing** via a `Router` over multiple named connections.
## Backends
Backends are selected by the connection URL; the abstraction is a single Rust
trait (`Backend`) plus a Python `BaseDialect` subclass:
```python
await YaraOrm.init("postgres://user@localhost/db") # PostgreSQL (tokio-postgres)
await YaraOrm.init("mysql://user:pass@localhost/db") # MySQL/MariaDB (mysql_async)
await YaraOrm.init("sqlite:///path/to/app.db") # SQLite (rusqlite)
```
The SQLite backend maps rich types (uuid/json/datetime/decimal) onto SQLite's
storage classes and reconstructs them on read from the declared column type, so
the model layer is identical across backends.
## Migrations
A Django/Tortoise-style, operation-based migration system. Migrations are
auto-generated from model changes and **backend-portable** β the same operations
render to PostgreSQL, MySQL or SQLite DDL at apply time. Applied migrations are tracked
in an `orm_migrations` table.
```bash
# autodetect model changes -> migrations/0001_initial.py
python -m yara_orm --models myapp.models makemigrations --name initial
# preview SQL without running it (per the target dialect)
python -m yara_orm --db sqlite:///app.db --models myapp.models sqlmigrate 0001_initial
# apply / revert / inspect
python -m yara_orm --db postgres://localhost/app --models myapp.models upgrade
python -m yara_orm --db postgres://localhost/app --models myapp.models downgrade
python -m yara_orm --db postgres://localhost/app --models myapp.models history
```
Each migration is a `class Migration(m.Migration)` whose `operations` are built
from live field objects: `CreateModel`, `DeleteModel`, `AddField`, `RemoveField`,
`AlterField`, `AddIndex`, `RemoveIndex`, plus hand-written renames
(`RenameModel` / `RenameField` / `RenameIndex`), constraints (`AddConstraint` /
`RemoveConstraint` / `RenameConstraint` with `UniqueConstraint` / `CheckConstraint`)
and `RunSQL` / `RunPython` for data migrations. `makemigrations` emits the
idempotent analogs (`CreateModelIfNotExists`, `AddFieldIfNotExists`, β¦) and detects
`AlterField` automatically. The same commands are available programmatically via
`yara_orm.MigrationManager`.
## Performance
Median of 5 runs, Python 3.12, 5000 rows β Yara ORM is fastest (or tied) on
every operation measured on PostgreSQL **and MySQL**, and wins everything
throughput-shaped on SQLite. Cells show Yara ORM's time and each competitor's
slowdown factor (>1 means Yara ORM is faster). Full methodology and tables in
[`benchmarks/`](benchmarks/).
### PostgreSQL 18

| operation | yara-orm | vs Tortoise | vs SQLAlchemy | vs Pony |
|---------------|---------:|------------:|--------------:|--------:|
| bulk_insert | 14.7 ms | 1.6Γ | 4.6Γ | 14.9Γ |
| single_insert | 34.2 ms | 2.3Γ | 4.4Γ | 1.8Γ |
| fetch_all | 3.5 ms | 4.8Γ | 6.1Γ | 9.8Γ |
| count | 0.3 ms | 1.9Γ | 3.2Γ | 1.5Γ |
| group_by | 0.7 ms | 1.6Γ | 1.9Γ | 3.1Γ |
| filter | 2.2 ms | 3.9Γ | 3.5Γ | 8.1Γ |
| get_by_pk | 65.0 ms | 3.0Γ | 4.4Γ | 1.3Γ |
| update | 3.2 ms | 1.1Γ | 1.2Γ | 37.3Γ |
| delete | 0.7 ms | 1.2Γ | 1.6Γ | 135.6Γ |
### MySQL 8.4
Same workload against MySQL (Tortoise over asyncmy, SQLAlchemy over aiomysql,
Pony over pymysql):

| operation | yara-orm | vs Tortoise | vs SQLAlchemy | vs Pony |
|---------------|----------:|------------:|--------------:|--------:|
| bulk_insert | 46.0 ms | 1.0Γ | 17.4Γ | 9.4Γ |
| single_insert | 693.7 ms | 1.1Γ | 1.3Γ | 1.1Γ |
| fetch_all | 5.6 ms | 6.0Γ | 6.9Γ | 8.4Γ |
| count | 0.7 ms | 1.4Γ | 1.7Γ | 1.1Γ |
| group_by | 1.2 ms | 1.2Γ | 1.7Γ | 2.0Γ |
| filter | 3.4 ms | 5.3Γ | 4.8Γ | 7.3Γ |
| get_by_pk | 110.9 ms | 2.1Γ | 4.9Γ | 2.8Γ |
| update | 7.2 ms | 1.1Γ | 1.5Γ | 32.5Γ |
| delete | 4.9 ms | 1.0Γ | 1.1Γ | 42.9Γ |
(`single_insert` is dominated by InnoDB's per-commit fsync β every ORM pays
it; `get_by_pk` and `single_insert` include the Docker-network round trip.)
### SQLite

Yara ORM wins everything throughput-shaped (fetch_all 6β16Γ, filter 4β14Γ,
bulk_insert 1.8β80Γ) and trails only the two latency-bound point ops, where
the per-statement asyncio bridge costs tens of Β΅s against in-process sync
drivers β the opt-in `sqlite://...?sync_fast_path=1` URL flag removes that
bridge entirely (point queries ~7Γ faster).
Speed comes from the Rust hot path, **positional row decoding** (no per-row dict
or column-name allocation), **compiled-SQL + prepared-statement caching**, and
connection pooling (see
[Performance](https://vsdudakov.github.io/yara-orm/performance/)). Run it
yourself with `make bench` / `make bench-mysql` / `make bench-sqlite`.
## Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββ
β Python (python/yara_orm) ................. β
β Model / metaclass ....... schema + ORM APIβ
β QuerySet ................ lazy SQL builderβ
β fields .................... abstract typesβ
β dialects ................ per-DB SQL rulesβ
βββββββββββββββββ¬ββββββββββββββββββββββββββββββ
β sql + params (PyO3 / asyncio bridge)
βββββββββββββββββΌββββββββββββββββββββββββββββββ
β Rust (rust/src) β yara_orm._engine ..... β
β Engine ...................... async facadeβ
β Backend trait .............. pluggable DBsβ
β PgBackend ............... tokio-postgresβ
β MySqlBackend ................ mysql_asyncβ
β SqliteBackend ................. rusqliteβ
β Value .................. PyβRustβSQL typesβ
βββββββββββββββββββββββββββββββββββββββββββββββ
```
- **Rust owns** pooling (deadpool), binding, type conversion and decoding.
- **Python owns** the model layer and SQL generation.
- **Adding a database** = a new `Backend` impl + scheme match in
`rust/src/backend/mod.rs`, plus a `BaseDialect` subclass in
`python/yara_orm/dialects.py`. The model layer never changes.
## Development
```bash
git clone https://github.com/vsdudakov/yara-orm
cd yara-orm
make dev # create .venv313 and install dev tools (maturin, ruff, ty, pytest)
make build # compile the Rust engine into the venv (maturin develop)
make lint # ruff check + ruff format --check + ty
make test # pytest against $DB (default postgres://localhost/orm_demo)
make cov # tests with the 100% coverage gate
make bench # 4-way benchmark (needs `make bench-setup` once; Python β€ 3.12 for Pony)
make bench-mysql # same 4-way comparison on MySQL
make bench-sqlite # same 4-way comparison on SQLite
```
Requires a Rust toolchain (`rustup`), a local PostgreSQL for the Postgres tests
and a local MySQL for the MySQL tests; the SQLite tests are self-contained.
## Contributing
Issues and pull requests are welcome. Please run `make lint` and `make cov`
(both must be green β lint clean and 100% coverage) before opening a PR.
## Sponsor
Yara ORM is MIT-licensed and developed in the open. If it saves your project
time β or you'd like to support continued work on the Rust engine, backends and
docs β please consider [**sponsoring on GitHub**](https://github.com/sponsors/vsdudakov).
Every bit helps and is hugely appreciated. β€οΈ
## License
[MIT](LICENSE.md) Β© Yara ORM contributors