This document captures the intended architecture for SQLModel Rust as a first-principles Rust implementation. It complements:
Use this document for design decisions and invariants. Use EXISTING_SQLMODEL_STRUCTURE.md as behavior spec.
- Keep the user-facing experience close to Python SQLModel while staying idiomatic in Rust.
- Prefer compile-time guarantees (derive macros, static metadata, type checking).
- Keep runtime simple and predictable (no reflection-based ORM behavior).
- Enforce cancel-correct async and structured concurrency via asupersync.
- Keep dependencies minimal and focused.
The workspace is intentionally split into small crates with clear boundaries.
-
sqlmodel: Facade crate; re-exports the public API (Model,Connection, query builders, macros, schema/session/pool APIs). -
sqlmodel-core: Core types and traits. OwnsModel,Connection,TransactionOps,Value,Row,FieldInfo, and shared error types. -
sqlmodel-macros: Proc macros (derive(Model), validation derives). Generates static model metadata and conversion logic at compile time. -
sqlmodel-query: Query DSL, builders, expression system, select/polymorphic loading, and dialect SQL generation. -
sqlmodel-schema: DDL generation and migration execution primitives. -
sqlmodel-session: Unit-of-work and identity map semantics. -
sqlmodel-pool: Connection pooling primitives, health, and routing support. -
Driver crates:
sqlmodel-sqlite,sqlmodel-postgres,sqlmodel-mysqlprovide wire/driver implementations behind theConnectiontrait.
sqlmodel-coreis the base.sqlmodel-query,sqlmodel-schema,sqlmodel-session,sqlmodel-pool, drivers depend onsqlmodel-core.sqlmodeldepends on all public sub-crates and re-exports them.sqlmodel-macrosdepends onsqlmodel-coremetadata types for generated code shape.
Model is static metadata + row conversion contract:
- Static table metadata:
TABLE_NAME,PRIMARY_KEY,fields(),inheritance(). - Runtime conversions:
to_row(),from_row(),primary_key_value(),is_new(). - Joined-inheritance support:
joined_parent_row()for joined child models with#[sqlmodel(parent)]embedded base.
Design intent:
- No runtime schema introspection is required for normal model operations.
- All per-model metadata is generated at compile time.
Connection abstracts query/execute/transaction lifecycle. Drivers own protocol details.
TransactionOps provides transactional query/execute and commit/rollback/savepoint behavior.
Design intent:
- Query builders produce SQL + params; drivers execute them.
- Session and builders compose against trait contracts, not concrete drivers.
All async DB operations are designed to:
- accept
&Cx - return
Outcome<T, Error> - remain cancel-correct and budget-aware
This is an architectural invariant across query/session/driver layers.
- Macro entry points:
select!,insert!,insert_many!,update!,delete! - Fluent builders for filters, joins, ordering, limits, conflict behavior, and returning.
- Builders are typed by model (
Select<M>,InsertBuilder<M>, etc.).
Dialect is carried through query generation. Placeholder conventions are invariant:
- PostgreSQL:
$1,$2, ... - SQLite:
?1,?2, ... - MySQL:
?
Builders produce dialect-specific SQL with deterministic parameter ordering.
When a query must hydrate multiple logical model shapes from one row (e.g. eager loading, joined inheritance polymorphism), columns are projected with alias format:
table__column
Example:
people.id AS people__idstudents.grade AS students__grade
This table__col aliasing convention is required for stable prefix-based hydration.
The architecture supports three mapping strategies represented in InheritanceInfo.
- One physical table for base + children.
- Base defines discriminator column.
- Children define discriminator values.
- Child queries apply implicit discriminator filter.
Polymorphic strategy:
- Base reads discriminator and hydrates the matching Rust type.
- No additional table join is required.
- Base and each child have separate physical tables.
- Child PK is also FK to base PK.
- Child models embed base via
#[sqlmodel(parent)].
Insert/update/delete strategy:
- Operations touching a child may need coordinated base+child statements in one transaction.
- For inserts with generated PKs, base insertion occurs first, PK is propagated to child row.
Polymorphic query strategy:
- Base SELECT with explicit
LEFT JOIN(s) to child table(s). - Full prefixed projection for base and children (
table__col). - Hydration chooses variant based on non-null child prefixes.
- Ambiguity (more than one child prefix non-null) is treated as an error.
- Each type owns independent table mapping.
- No DB-level parent-child FK coupling required.
sqlmodel-schema is responsible for generated DDL and migration execution.
Key behavior:
- joined inheritance child DDL includes FK from child PK columns to parent PK columns
- single-table inheritance children do not create independent physical tables
- schema builders remain model-metadata driven, not reflection-driven
sqlmodel-session provides a unit-of-work boundary:
- tracks object states (new/dirty/deleted)
- flushes into database operations
- keeps identity map consistency by PK
- coordinates transactions for grouped operations
Design intent:
- explicit, predictable lifecycle
- no hidden lazy global state
- model-level operations funnel into query builders + connection contracts
- Compile-time metadata generation rather than runtime reflection.
- Minimal allocations where practical (reuse row/value structures, deterministic SQL emit).
- Explicit transactional composition for multi-table inheritance operations.
- Clear structured errors over implicit fallback behavior.
At the time of writing, remaining architectural follow-ups are tracked in beads.
-
bd-3bmd: Joined-table inheritance DML semantics for explicitWHERE/SETbuilder usage and ON CONFLICT edge behavior. -
bd-162: Epic umbrella for full SQLModel parity tracking.
Keep this section synchronized with FEATURE_PARITY.md and open beads issues.
These invariants should remain true unless explicitly revised:
- All async database APIs accept
&Cxand returnOutcome<_, Error>. - Query generation is dialect-aware with stable placeholder behavior.
- Multi-model hydration uses
table__colaliasing. - Joined inheritance child writes are coordinated across base+child tables.
sqlmodelremains a thin facade over focused sub-crates.- Core remains dependency-lean and avoids heavyweight ORM/database dependencies.