{"library":"sqlmodel","title":"SQLModel","description":"SQLModel is a Python library that unifies SQLAlchemy's ORM capabilities with Pydantic's data validation, simplifying interaction with SQL databases. It aims to reduce code duplication by using a single class definition for both database models and data schemas. SQLModel is currently in version 0.0.38 and maintains an active development cadence with frequent releases, often including bug fixes, dependency updates, and sometimes breaking changes.","status":"active","version":"0.0.38","language":"en","source_language":"en","source_url":"https://github.com/fastapi/sqlmodel","tags":["orm","sqlalchemy","pydantic","fastapi","database","sql","async"],"install":[{"cmd":"pip install sqlmodel","lang":"bash","label":"Standard Installation"},{"cmd":"pip install sqlmodel[asyncpg]","lang":"bash","label":"For PostgreSQL with Async"},{"cmd":"pip install sqlmodel[aiosqlite]","lang":"bash","label":"For SQLite with Async"}],"dependencies":[{"reason":"Core dependency for data validation and schema definition, version 2+ is required.","package":"pydantic","optional":false},{"reason":"Core dependency for ORM and database interaction, version 2+ is recommended.","package":"sqlalchemy","optional":false},{"reason":"Often used together for building APIs, offers seamless integration.","package":"fastapi","optional":true},{"reason":"Asynchronous PostgreSQL driver for async database operations.","package":"asyncpg","optional":true},{"reason":"Asynchronous SQLite driver for async database operations.","package":"aiosqlite","optional":true}],"imports":[{"symbol":"SQLModel","correct":"from sqlmodel import SQLModel"},{"symbol":"Field","correct":"from sqlmodel import Field"},{"symbol":"Session","correct":"from sqlmodel import Session"},{"symbol":"create_engine","correct":"from sqlmodel import create_engine"},{"note":"SQLModel's `select` provides enhanced type annotations and automatically handles `.scalars()` which SQLAlchemy's version doesn't.","wrong":"from sqlalchemy import select","symbol":"select","correct":"from sqlmodel import select"},{"note":"Async engine is imported directly from SQLAlchemy's async extension.","wrong":"from sqlmodel import create_async_engine","symbol":"create_async_engine","correct":"from sqlalchemy.ext.asyncio import create_async_engine"},{"note":"Async session is imported directly from SQLAlchemy's async extension.","wrong":"from sqlmodel import AsyncSession","symbol":"AsyncSession","correct":"from sqlalchemy.ext.asyncio import AsyncSession"}],"quickstart":{"code":"from typing import Optional\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\nclass Hero(SQLModel, table=True):\n    id: Optional[int] = Field(default=None, primary_key=True)\n    name: str\n    secret_name: str\n    age: Optional[int] = Field(default=None, index=True)\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\n# Or for in-memory:\n# sqlite_url = \"sqlite://\"\n\nengine = create_engine(sqlite_url, echo=True)\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\ndef create_heroes():\n    hero_1 = Hero(name=\"Deadpond\", secret_name=\"Dive Wilson\")\n    hero_2 = Hero(name=\"Spider-Boy\", secret_name=\"Pedro Parqueador\", age=16)\n    hero_3 = Hero(name=\"Rusty-Man\", secret_name=\"Tommy Sharp\", age=48)\n\n    with Session(engine) as session:\n        session.add(hero_1)\n        session.add(hero_2)\n        session.add(hero_3)\n\n        session.commit()\n\n        session.refresh(hero_1)\n        session.refresh(hero_2)\n        session.refresh(hero_3)\n\n        print(\"Created heroes:\", hero_1, hero_2, hero_3)\n\ndef select_heroes():\n    with Session(engine) as session:\n        statement = select(Hero).where(Hero.age >= 18)\n        results = session.exec(statement)\n        heroes = results.all()\n        print(\"Adult heroes:\", heroes)\n\ndef main():\n    create_db_and_tables()\n    create_heroes()\n    select_heroes()\n\nif __name__ == \"__main__\":\n    main()","lang":"python","description":"This quickstart demonstrates how to define a `SQLModel` table, create a database engine (using SQLite in this case), create the database tables, and then insert and query data. It showcases the combined power of Pydantic-like model definition with SQLAlchemy's ORM operations. The `echo=True` in `create_engine` will print SQL statements to the console."},"warnings":[{"fix":"Upgrade your Python environment to 3.10 or newer. For older Python versions, use SQLModel < 0.0.35.","message":"SQLModel versions 0.0.35 and higher require Python 3.10 or later.","severity":"breaking","affected_versions":">=0.0.35"},{"fix":"Upgrade Pydantic to version 2 (e.g., `pip install pydantic==2.*`). Be aware that Pydantic v2 has its own breaking changes. If you must use Pydantic v1, pin SQLModel to `<0.0.31` or use `pydantic<2`.","message":"SQLModel version 0.0.31 dropped support for Pydantic v1. It now requires Pydantic v2.","severity":"breaking","affected_versions":">=0.0.31"},{"fix":"Always use a new `Session` context manager for each logical unit of work. For FastAPI, use `Depends` to inject a session per request. Ensure all operations on a model instance occur within the same session that loaded it.","message":"SQLModel `Session` objects are not thread-safe and should be created per request/task, typically using a `with Session(engine) as session:` block. Detached objects (queried in one session, then used in another) can lead to unexpected behavior.","severity":"gotcha","affected_versions":"all"},{"fix":"Install the correct async driver (e.g., `pip install sqlmodel[aiosqlite]`). Use `create_async_engine` with a proper async database URL (e.g., `sqlite+aiosqlite:///./test.db`). Manage async sessions with `async with AsyncSession(engine) as session:`.","message":"For asynchronous database operations, you must use `sqlalchemy.ext.asyncio.create_async_engine` and `sqlalchemy.ext.asyncio.AsyncSession` (or `sqlmodel.ext.asyncio.Session` when available). Also, ensure you use an async-compatible database driver (e.g., `aiosqlite` for SQLite, `asyncpg` for PostgreSQL).","severity":"gotcha","affected_versions":"all"},{"fix":"Structure your code so model definitions are fully loaded before `SQLModel.metadata.create_all()` is invoked. For complex applications, consider using a database migration tool like Alembic.","message":"The `SQLModel.metadata.create_all(engine)` call must be executed *after* all your `SQLModel` classes have been defined. If models are in separate files, ensure they are imported before `create_all` is called.","severity":"gotcha","affected_versions":"all"},{"fix":"Use `from typing import TYPE_CHECKING` and import classes inside an `if TYPE_CHECKING:` block for type-checking tools. For example: `if TYPE_CHECKING: from .other_model import OtherModel`.","message":"When defining relationships between models (e.g., `Hero` and `Team`), circular import issues can arise with type annotations. Python's runtime cannot resolve these.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-06T00:00:00.000Z","next_check":"2026-07-05T00:00:00.000Z"}