Tortoise ORM
raw JSON → 1.1.7 verified Tue May 12 auth: no python install: verified quickstart: stale
Async ORM for Python inspired by Django ORM. Built on asyncio — requires async context. Current version: 1.1.7 (Mar 2026). v1.0 released 2024 — first stable release after years of 0.x. Breaking changes from 0.x: connections.close_all() removed, ConnectionHandler uses per-instance ContextVar storage. FastAPI integration changed from register_tortoise() to RegisterTortoise context manager. Does not work on serverless/Vercel without workarounds.
pip install tortoise-orm Common errors
error Tortoise is not initialised. ↓
cause Tortoise ORM models are used before `Tortoise.init()` has been successfully called and awaited to initialize database connections and mappings.
fix
Ensure
await Tortoise.init(...) is called at the application's startup, before any database operations involving models. error sqlite3.OperationalError: no such table: <table_name> ↓
cause The database table corresponding to a Tortoise ORM model has not been created or synchronized with the database schema.
fix
Call
await Tortoise.generate_schemas() after await Tortoise.init() during application startup to create the necessary tables. For production, a proper migration tool like Aerich is recommended. error RuntimeWarning: coroutine '...' was never awaited ↓
cause An asynchronous method (coroutine) from Tortoise ORM was called without the `await` keyword, causing it to return a coroutine object that was never executed.
fix
Prefix all async Tortoise ORM calls with
await, for example, await Tortoise.init(...), await model_instance.save(), await MyModel.all(). error AttributeError: module 'tortoise.contrib.fastapi' has no attribute 'register_tortoise' ↓
cause The `register_tortoise` function was removed in Tortoise ORM v1.0 and replaced by the `RegisterTortoise` context manager for FastAPI integration.
fix
Use the
RegisterTortoise context manager from tortoise.contrib.fastapi within your FastAPI application's startup/shutdown events to manage Tortoise ORM initialization and cleanup. error AttributeError: module 'tortoise.connections' has no attribute 'close_all' ↓
cause The `tortoise.connections.close_all()` function was removed in Tortoise ORM v1.0 and replaced by `Tortoise.close_connections()` for closing all database connections.
fix
Replace
tortoise.connections.close_all() with await Tortoise.close_connections() to ensure all active database connections are properly closed during application shutdown. Warnings
breaking connections.close_all() removed in v1.0. Raises AttributeError. ↓
fix Use Tortoise.close_connections() instead.
breaking Running multiple FastAPI apps in the same process (e.g., in tests) raises ConfigurationError: 'Global context fallback is already enabled'. Happens with lifespan-based testing. ↓
fix Pass _enable_global_fallback=False to RegisterTortoise for secondary apps.
gotcha Must use 'modules' dict when calling Tortoise.init() — must list all model module paths explicitly. Missing a module means those models are unknown to Tortoise and relations fail silently. ↓
fix modules={'models': ['myapp.models.user', 'myapp.models.post']} — list ALL model files.
gotcha tortoise-orm does not work on serverless/Vercel without workarounds. Connection pooling assumes long-running process — serverless cold starts cause 'connection pool is closed' errors. ↓
fix Not recommended for serverless. Use asyncpg directly or a serverless-compatible ORM.
gotcha generate_schemas=True in production silently drops and recreates tables if schema changes. Use Aerich (tortoise's migration tool) for production schema management. ↓
fix Set generate_schemas=False in production. Use aerich for migrations: pip install aerich
gotcha pydantic_model_creator() generates Pydantic models from Tortoise models. In v1.0, internal validator logic was cleaned up — custom PydanticMeta overrides may behave differently. ↓
fix Test pydantic_model_creator() output after upgrading to v1.0.
gotcha DB-specific drivers must be installed separately. 'pip install tortoise-orm' alone raises ImproperlyConfigured when connecting to PostgreSQL or MySQL. ↓
fix pip install 'tortoise-orm[asyncpg]' for PostgreSQL, 'tortoise-orm[asyncmy]' for MySQL, 'tortoise-orm[aiosqlite]' for SQLite.
breaking Database server is unreachable or connection refused. The application is configured to connect to a database (e.g., PostgreSQL on port 5432), but the server is not running or is not accessible at the specified host/port (e.g., 127.0.0.1:5432). ↓
fix Ensure your database server (e.g., PostgreSQL) is running and accessible from the application's environment on the configured host and port. Verify database server logs, firewall rules, and the connection string (TORTOISE_CONFIG) used by Tortoise-ORM.
Install
pip install 'tortoise-orm[accel]' pip install 'tortoise-orm[asyncpg]' Install compatibility verified last tested: 2026-05-12
python os / libc variant status wheel install import disk
3.10 alpine (musl) accel - - 0.00s 33.9M
3.10 alpine (musl) asyncpg - - 0.00s 32.0M
3.10 alpine (musl) tortoise-orm - - 0.00s 23.9M
3.10 slim (glibc) accel - - 0.00s 38M
3.10 slim (glibc) asyncpg - - 0.00s 35M
3.10 slim (glibc) tortoise-orm - - 0.00s 24M
3.11 alpine (musl) accel - - 0.00s 36.5M
3.11 alpine (musl) asyncpg - - 0.00s 34.6M
3.11 alpine (musl) tortoise-orm - - 0.00s 26.2M
3.11 slim (glibc) accel - - 0.00s 40M
3.11 slim (glibc) asyncpg - - 0.00s 38M
3.11 slim (glibc) tortoise-orm - - 0.00s 27M
3.12 alpine (musl) accel - - 0.00s 30.1M
3.12 alpine (musl) asyncpg - - 0.00s 27.8M
3.12 alpine (musl) tortoise-orm - - 0.00s 17.8M
3.12 slim (glibc) accel - - 0.00s 35M
3.12 slim (glibc) asyncpg - - 0.00s 31M
3.12 slim (glibc) tortoise-orm - - 0.00s 18M
3.13 alpine (musl) accel - - 0.00s 29.3M
3.13 alpine (musl) asyncpg - - 0.00s 27.1M
3.13 alpine (musl) tortoise-orm - - 0.00s 17.2M
3.13 slim (glibc) accel - - 0.00s 34M
3.13 slim (glibc) asyncpg - - 0.00s 31M
3.13 slim (glibc) tortoise-orm - - 0.00s 18M
3.9 alpine (musl) accel - - 0.00s 34.6M
3.9 alpine (musl) asyncpg - - 0.00s 32.7M
3.9 alpine (musl) tortoise-orm - - 0.00s 24.7M
3.9 slim (glibc) accel - - 0.00s 38M
3.9 slim (glibc) asyncpg - - 0.00s 36M
3.9 slim (glibc) tortoise-orm - - 0.00s 25M
Imports
- RegisterTortoise (FastAPI — v1.0+ recommended) wrong
# Old pattern — register_tortoise with on_event (deprecated in FastAPI) from tortoise.contrib.fastapi import register_tortoise app = FastAPI() register_tortoise( app, db_url='...', modules={'models': ['myapp.models']}, generate_schemas=True, )correctfrom contextlib import asynccontextmanager from fastapi import FastAPI from tortoise.contrib.fastapi import RegisterTortoise @asynccontextmanager async def lifespan(app: FastAPI): async with RegisterTortoise( app, db_url='postgres://user:pass@localhost/mydb', modules={'models': ['myapp.models']}, generate_schemas=True, ): yield app = FastAPI(lifespan=lifespan) - Tortoise.init (standalone scripts) wrong
from tortoise import connections await connections.close_all() # removed in v1.0correctfrom tortoise import Tortoise async def main(): await Tortoise.init( db_url='sqlite://db.sqlite3', modules={'models': ['myapp.models']} ) await Tortoise.generate_schemas() user = await User.create(name='Alice') users = await User.filter(name='Alice').all() await Tortoise.close_connections() import asyncio asyncio.run(main())
Quickstart stale last tested: 2026-04-23
# pip install 'tortoise-orm[asyncpg]'
from tortoise import Tortoise, fields
from tortoise.models import Model
import asyncio
class User(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=50)
email = fields.CharField(max_length=120, unique=True)
class Meta:
table = 'users'
async def main():
await Tortoise.init(
db_url='postgres://user:pass@localhost/mydb',
modules={'models': ['__main__']}
)
await Tortoise.generate_schemas()
# Create
user = await User.create(name='Alice', email='alice@example.com')
# Query
users = await User.filter(name='Alice').all()
user = await User.get(id=1)
user = await User.get_or_none(email='alice@example.com')
await Tortoise.close_connections()
asyncio.run(main())