Cloud Parts

Tortoise ORM

An async-native Python ORM with a Django-style API: models as classes, await Model.filter(...) queries, and built-in migrations since 1.0.

What it is
Object-relational mapping (full orms)
Type
Open source
Made by
Tortoise ORM contributors
License
Apache 2.0
Facts checked
9 October 2026

What it is

Tortoise ORM was built for asyncio applications. You define models by subclassing Model and declaring fields, including ForeignKeyField and ManyToManyField relations, and every database call is awaited: await Order.create(...), await obj.save(), await Order.filter(amount__gt=100). Filters use Django’s double-underscore style (name__icontains, customer__name) and can follow relations into joins. Related objects aren’t loaded behind your back; you await them or load them up front with fetch_related and prefetch_related.

It runs on CPython 3.10 and later and talks to SQLite (aiosqlite), PostgreSQL (asyncpg or psycopg), MySQL and MariaDB (asyncmy or aiomysql), and Microsoft SQL Server and Oracle through asyncodbc. Version 1.0, released in February 2026, added a native migration framework (tortoise makemigrations, tortoise migrate, tortoise sqlmigrate) that replaces the separate Aerich tool, moved all ORM state into explicit TortoiseContext objects, and added PostgreSQL full-text search. Contrib modules register Tortoise in a FastAPI app’s lifespan and generate Pydantic models from Tortoise models with pydantic_model_creator.

Why teams pick it

  • Async from the ground up: every query is awaited, and a contrib module wires it into a FastAPI app’s lifespan
  • Familiar to Django users: model classes, filter and exclude with field__lookup arguments, and Django-like migration commands
  • Migrations are built in since 1.0, with autodetection, reversible operations, RunPython and RunSQL, and a command to preview the SQL
  • Small API surface for CRUD-heavy services: create, save, filter and prefetch without sessions to manage

Watch out for

  • Async only: synchronous scripts or frameworks need an event loop around every call (run_async or asyncio.run)
  • Version 1.0 (February 2026) broke existing code: Python 3.10+, use_tz on by default, a new context-first architecture and removal of the old test helpers
  • A smaller ecosystem: about 5,600 GitHub stars against more than 12,000 for SQLAlchemy, which also does async through AsyncSession and supports external dialects
  • Its built-in migrations are new; projects started before 1.0 used Aerich, which the docs now call a legacy alternative

Alternatives

What all full orms have in common →

How it fits with other technologies

Models, a filtered query across a relation, and an explicit prefetch (SQLite in memory) · python

from tortoise import Tortoise, fields, run_async
from tortoise.models import Model

class Customer(Model):
    id = fields.IntField(primary_key=True)
    name = fields.CharField(max_length=100)

class Order(Model):
    id = fields.IntField(primary_key=True)
    amount = fields.IntField()
    customer = fields.ForeignKeyField("models.Customer", related_name="orders")

async def main():
    await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})
    await Tortoise.generate_schemas()  # dev only; use `tortoise makemigrations` in production

    ada = await Customer.create(name="Ada")
    await Order.create(amount=120, customer=ada)
    await Order.create(amount=80, customer=ada)

    big = await Order.filter(amount__gt=100, customer__name="Ada").count()
    print(big)  # 1

    await ada.fetch_related("orders")  # relations load only when you await them
    print([o.amount for o in ada.orders])  # [120, 80]

    await Tortoise.close_connections()

run_async(main())

Tortoise ORM and SQLAlchemy#

SQLAlchemy has supported asyncio since version 1.4, so async alone is no longer a reason to pick Tortoise. The difference is the API style and how much each one covers.

Tortoise ORMSQLAlchemy
StyleDjango-like models; await Model.filter(field__lookup=...)Mapped classes used through a Session, plus Core for building SQL expressions
Sync and asyncAsync onlySync, plus AsyncSession and async engines since 1.4
Loading relationsAwait the relation or fetch_related / prefetch_relatedEager loading, or awaitable_attrs under asyncio, where implicit lazy loading would fail
MigrationsBuilt in since 1.0 (tortoise makemigrations)Alembic, a separate project from the SQLAlchemy authors
DatabasesSQLite, PostgreSQL, MySQL and MariaDB, SQL Server, OracleThe same five built in, plus external dialects

See it in a real stack

No architecture uses Tortoise ORM yet. Drop it into the playground and wire it up yourself.Open playground →
Where it came from2018–2026

Andrey Bondar published Tortoise ORM in March 2018. The goal, as the README still puts it, was a lightweight, async-native object-relational mapper for Python “with a familiar Django-like API”. Nickolas Grigoriadis and Jinlong Peng have since made the most commits.

Version 0.16.0 in March 2020 added automatic Pydantic models built from Tortoise models. Migrations stayed outside the core: Aerich, a separate tool, was integrated into the install in October 2020. Tortoise 1.0 arrived in February 2026 after almost eight years of 0.x releases, with native migrations, explicit contexts in place of global state, and database schema support for PostgreSQL and SQL Server.

Why it’s built this way

Copy Django’s API, not SQLAlchemy’s
The docs describe Tortoise as “inspired by Django”: model classes, querysets and double-underscore lookups such as name__icontains carry over, so the main new thing to learn is await.
Async-only
Every database call returns an awaitable, so there is one code path, built for asyncio frameworks, instead of a sync API with async bolted on.
No implicit lazy loading
Loading a relation means a database round trip, which in async code has to be awaited. Tortoise makes that explicit with awaitable relations and fetch_related.
Migrations moved into the core in 1.0
Migrations used to live in Aerich, a separate tool. The 1.0 framework autodetects model changes with makemigrations and migrate commands, and Aerich’s own README now sends 1.0 users to it.

Timeline

  1. 2018

    Andrey Bondar releases Tortoise ORM 0.1.0 in March

  2. 2020

    0.16.0 in March builds Pydantic models from Tortoise models

  3. 2020

    Aerich migrations integrated into the install in October

  4. 2026

    Tortoise ORM 1.0 in February adds native migrations

Sources13 · facts checked 9 October 2026

Improve this page on GitHub