SQLModel
SQLModel sits on SQLAlchemy and Pydantic, letting one class definition serve as both a database table and a validation schema. It comes from the author of FastAPI and is designed to fit that stack.
The appeal is the removal of a duplication that is otherwise unavoidable. Without it a typical backend defines the same entity three times — a SQLAlchemy model, a Pydantic schema for requests, another for responses — and every field change has to be made in all three. SQLModel collapses that.
Where the collapse holds and where it does not
For straightforward CRUD it holds well, and the productivity gain is real rather than marginal. The stack in Status Alganize is essentially this pattern, and Study Duel extends it without difficulty.
It stops holding where the API contract and the database schema legitimately differ, which happens sooner than expected:
- A password hash is a column and must never be a response field.
- A creation request has no ID; a response does.
- A response often wants computed or joined fields that are not columns.
SQLModel handles this by having you define additional models for those cases — which is the three-model pattern reappearing, now with the base class shared. That is still better than full duplication, and it is worth knowing that the collapse is partial rather than total, so the promise of one model per entity does not survive contact with a real API.
What surfaces underneath
SQLAlchemy is not hidden so much as deferred. Anything beyond basic queries — complex joins, window functions, eager loading strategies, bulk operations — means working with SQLAlchemy directly, and SQLModel’s documentation does not cover it. In practice a project using SQLModel becomes a project using SQLAlchemy with a convenience layer, so being willing to read SQLAlchemy’s documentation is a prerequisite rather than an escape hatch.
Migrations remain a separate discipline: Alembic is required, and SQLModel’s convenience does not extend to schema evolution.
For a research-oriented backend touching spatial data, PostGIS types need explicit handling since they are outside SQLModel’s core vocabulary.
See also: ORMs generally, Pydantic, Alembic, FastAPI, and PostgreSQL.