skills/sqlmodel/SKILL.md
SQLModel persistence patterns for Python services and applications. Covers model design, async sessions, relationships, Alembic migrations, query optimization, N+1 prevention, and production-safe schema changes. Load when working with SQLModel, Alembic, relationships, async database layers, or SQLAlchemy-backed persistence in Python.
npx skillsauth add oornnery/.agents sqlmodelInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Persistence modeling, async sessions, relationships, migrations, query loading with SQLModel and Alembic.
Use for persistence modeling, async sessions, relationships, transactions, migrations, query optimization with SQLModel.
python for general Python conventions, tooling, FastAPI usagearch when repo boundaries, domain separation, layering matterdesign when API contract and persistence shape must stay decoupledquality when query bugs, regressions, migration failures need tighter guardssecurity when persistence changes touch auth data, tenant isolation, secrets, unsafe raw SQLreferences/advanced-models.md -- advanced model patterns, relationships, inheritance, mixins, field types, indexes, constraintsreferences/migrations.md -- Alembic setup, schema/data migrations, rollback patterns, prod workflow, troubleshootingreferences/queries-optimization.md -- query patterns, eager loading, N+1 prevention, bulk ops, profiling, perf testingassets/models.py -- table, create, read, update, timestamps, enums, many-to-many patternsscripts/init.py -- starter script to init DB from imported SQLModel metadatascripts/migrate.sh -- migration helper wrapper around Alembic commandsDefaults, async patterns, guardrails for day-to-day work.
uv add sqlmodel sqlalchemy[asyncio] alembic
uv add asyncpg
Start with:
from sqlmodel import Field, SQLModel
class UserBase(SQLModel):
name: str = Field(max_length=100)
email: str = Field(max_length=255, unique=True)
class User(UserBase, table=True):
id: int | None = Field(default=None, primary_key=True)
hashed_password: str
class UserCreate(UserBase):
password: str = Field(min_length=8)
class UserPublic(UserBase):
id: int
class UserUpdate(SQLModel):
name: str | None = None
email: str | None = None
Separate models because table shape, write input, public response rarely share responsibilities.
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from sqlmodel.ext.asyncio.session import AsyncSession
engine = create_async_engine(
"postgresql+asyncpg://...",
pool_size=20,
max_overflow=10,
)
async_session = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
expire_on_commit=False keeps returned objects usable after commit boundaries in async workflows.
from collections.abc import AsyncGenerator
from typing import Annotated
from fastapi import Depends
from sqlmodel.ext.asyncio.session import AsyncSession
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with async_session() as session:
yield session
SessionDep = Annotated[AsyncSession, Depends(get_session)]
One session per request or job boundary. Keep transaction scope explicit.
from sqlalchemy.orm import selectinload
from sqlmodel import Field, Relationship, SQLModel, select
class Team(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
members: list["User"] = Relationship(back_populates="team")
statement = select(Team).options(selectinload(Team.members))
In async code, prefer explicit loading over accidental lazy loading. Default selectinload for collections unless query shape clearly favors join.
alembic init -t async alembic
alembic revision --autogenerate -m "add users table"
alembic upgrade head
Set target_metadata = SQLModel.metadata in alembic/env.py.
Review autogenerated migrations before applying. Do not trust autogenerate blindly for destructive, data-sensitive, or prod-facing changes.
For prod-heavy changes, load references/migrations.md.
For deeper query patterns, load references/queries-optimization.md.
For advanced patterns, load references/advanced-models.md.
expire_on_commit=False for async sessions unless specific reason not toselectinload or another explicit eager-loading strategy -- prevent N+1async with session.begin() for multi-step transactionsWHERE, ORDER BY, relationship joinsdevelopment
--- name: verification description: Discover and run project validation gates: format, lint, typecheck, LSP diagnostics, tests, build, static security checks, dependency audits, and RTK output handling. Use before claiming work is complete, when fixing broken checks, or when setting up a validation plan. --- # Verification Use this skill to prove changes with the strongest practical checks the repo already supports. ## Discovery Order 1. Read task aliases: `package.json`, `pyproject.toml`, `
tools
Build, review, or validate standalone Python scripts run with uv inline metadata. Use for one-file automation, operational scripts, script dependencies, shebangs, idempotency, safety, representative runs, and promoting scripts to packages.
development
Build, review, or validate Python packages and libraries where public API stability, packaging metadata, imports, examples, changelogs, build output, and compatibility matter.
tools
Build, review, or validate Python command-line applications and terminal tools. Use for argparse, Typer, Rich, Textual-adjacent CLI UX, stdout/stderr contracts, exit codes, automation-friendly flags, help output, and CLI tests.