{"id":163,"library":"tortoise-orm","title":"Tortoise ORM","description":"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.","status":"active","version":"1.1.7","language":"python","source_language":"en","source_url":"https://github.com/tortoise/tortoise-orm","tags":["tortoise-orm","orm","async","asyncio","fastapi","postgresql","python"],"install":[{"cmd":"pip install tortoise-orm","lang":"bash","label":"Python (pure — no C deps)"},{"cmd":"pip install 'tortoise-orm[accel]'","lang":"bash","label":"Python (with C accelerators — faster)"},{"cmd":"pip install 'tortoise-orm[asyncpg]'","lang":"bash","label":"Python (with asyncpg for PostgreSQL)"}],"dependencies":[{"reason":"Required for PostgreSQL. Install via tortoise-orm[asyncpg].","package":"asyncpg","optional":true},{"reason":"Required for SQLite async. Install via tortoise-orm[aiosqlite].","package":"aiosqlite","optional":true},{"reason":"Required for MySQL. Install via tortoise-orm[asyncmy].","package":"asyncmy","optional":true}],"imports":[{"note":"register_tortoise() still works but uses deprecated FastAPI on_event hooks. Use RegisterTortoise async context manager with FastAPI lifespan for v1.0+ style.","wrong":"# Old pattern — register_tortoise with on_event (deprecated in FastAPI)\nfrom tortoise.contrib.fastapi import register_tortoise\napp = FastAPI()\nregister_tortoise(\n    app,\n    db_url='...',\n    modules={'models': ['myapp.models']},\n    generate_schemas=True,\n)","symbol":"RegisterTortoise (FastAPI — v1.0+ recommended)","correct":"from contextlib import asynccontextmanager\nfrom fastapi import FastAPI\nfrom tortoise.contrib.fastapi import RegisterTortoise\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    async with RegisterTortoise(\n        app,\n        db_url='postgres://user:pass@localhost/mydb',\n        modules={'models': ['myapp.models']},\n        generate_schemas=True,\n    ):\n        yield\n\napp = FastAPI(lifespan=lifespan)"},{"note":"connections.close_all() removed in v1.0. Use Tortoise.close_connections() instead.","wrong":"from tortoise import connections\nawait connections.close_all()  # removed in v1.0","symbol":"Tortoise.init (standalone scripts)","correct":"from tortoise import Tortoise\n\nasync def main():\n    await Tortoise.init(\n        db_url='sqlite://db.sqlite3',\n        modules={'models': ['myapp.models']}\n    )\n    await Tortoise.generate_schemas()\n\n    user = await User.create(name='Alice')\n    users = await User.filter(name='Alice').all()\n\n    await Tortoise.close_connections()\n\nimport asyncio\nasyncio.run(main())"}],"quickstart":{"code":"# pip install 'tortoise-orm[asyncpg]'\nfrom tortoise import Tortoise, fields\nfrom tortoise.models import Model\nimport asyncio\n\nclass User(Model):\n    id = fields.IntField(pk=True)\n    name = fields.CharField(max_length=50)\n    email = fields.CharField(max_length=120, unique=True)\n\n    class Meta:\n        table = 'users'\n\nasync def main():\n    await Tortoise.init(\n        db_url='postgres://user:pass@localhost/mydb',\n        modules={'models': ['__main__']}\n    )\n    await Tortoise.generate_schemas()\n\n    # Create\n    user = await User.create(name='Alice', email='alice@example.com')\n\n    # Query\n    users = await User.filter(name='Alice').all()\n    user = await User.get(id=1)\n    user = await User.get_or_none(email='alice@example.com')\n\n    await Tortoise.close_connections()\n\nasyncio.run(main())","lang":"python","description":"Tortoise ORM v1.x standalone script with PostgreSQL."},"warnings":[{"fix":"Use Tortoise.close_connections() instead.","message":"connections.close_all() removed in v1.0. Raises AttributeError.","severity":"breaking","affected_versions":">= 1.0"},{"fix":"Pass _enable_global_fallback=False to RegisterTortoise for secondary apps.","message":"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.","severity":"breaking","affected_versions":">= 1.0"},{"fix":"modules={'models': ['myapp.models.user', 'myapp.models.post']} — list ALL model files.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Not recommended for serverless. Use asyncpg directly or a serverless-compatible ORM.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Set generate_schemas=False in production. Use aerich for migrations: pip install aerich","message":"generate_schemas=True in production silently drops and recreates tables if schema changes. Use Aerich (tortoise's migration tool) for production schema management.","severity":"gotcha","affected_versions":"all"},{"fix":"Test pydantic_model_creator() output after upgrading to v1.0.","message":"pydantic_model_creator() generates Pydantic models from Tortoise models. In v1.0, internal validator logic was cleaned up — custom PydanticMeta overrides may behave differently.","severity":"gotcha","affected_versions":">= 1.0"},{"fix":"pip install 'tortoise-orm[asyncpg]' for PostgreSQL, 'tortoise-orm[asyncmy]' for MySQL, 'tortoise-orm[aiosqlite]' for SQLite.","message":"DB-specific drivers must be installed separately. 'pip install tortoise-orm' alone raises ImproperlyConfigured when connecting to PostgreSQL or MySQL.","severity":"gotcha","affected_versions":"all"},{"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.","message":"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).","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T09:11:03.765Z","next_check":"2026-06-24T00:00:00.000Z","problems":[{"fix":"Ensure `await Tortoise.init(...)` is called at the application's startup, before any database operations involving models.","cause":"Tortoise ORM models are used before `Tortoise.init()` has been successfully called and awaited to initialize database connections and mappings.","error":"Tortoise is not initialised."},{"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.","cause":"The database table corresponding to a Tortoise ORM model has not been created or synchronized with the database schema.","error":"sqlite3.OperationalError: no such table: <table_name>"},{"fix":"Prefix all async Tortoise ORM calls with `await`, for example, `await Tortoise.init(...)`, `await model_instance.save()`, `await MyModel.all()`.","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.","error":"RuntimeWarning: coroutine '...' was never awaited"},{"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.","cause":"The `register_tortoise` function was removed in Tortoise ORM v1.0 and replaced by the `RegisterTortoise` context manager for FastAPI integration.","error":"AttributeError: module 'tortoise.contrib.fastapi' has no attribute 'register_tortoise'"},{"fix":"Replace `tortoise.connections.close_all()` with `await Tortoise.close_connections()` to ensure all active database connections are properly closed during application shutdown.","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.","error":"AttributeError: module 'tortoise.connections' has no attribute 'close_all'"}],"ecosystem":"pypi","meta_description":null,"install_score":80,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"33.9M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"32.0M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"23.9M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"38M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"35M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"24M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"36.5M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"34.6M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"26.2M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"40M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"38M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"27M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"30.1M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"27.8M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"17.8M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"35M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"31M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"18M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"29.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"27.1M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"17.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"34M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"31M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"18M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"34.6M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"32.7M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"24.7M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"accel","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"38M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"asyncpg","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"36M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.1,"disk_size":"25M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}