Auto-activate for sqlalchemy imports, mapped_column, DeclarativeBase. Produces SQLAlchemy 2.0+ ORM models, async sessions, engine configurations, and query patterns. Use when: defining SQLAlchemy models, writing ORM queries, configuring engines/sessions, using select() statements, managing relationships, or working with asyncio sessions. Not for raw SQL without ORM (see postgres/mysql), or Advanced Alchemy patterns (see advanced-alchemy).
From flownpx claudepluginhub cofin/flow --plugin flowThis skill uses the workspace's default tool permissions.
references/async.mdreferences/engine.mdreferences/events.mdreferences/migrations.mdreferences/models.mdreferences/queries.mdreferences/relationships.mdreferences/sessions.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
SQLAlchemy 2.0 uses Mapped[] type annotations, mapped_column(), and select() statements throughout. Legacy patterns (Column(), session.query()) are never used.
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String, Text, DateTime, func
from datetime import datetime
from typing import Optional
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
# Required column -- Mapped[type] (non-optional = NOT NULL)
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100))
# Nullable column -- use Optional
bio: Mapped[Optional[str]] = mapped_column(Text)
# Server default
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()
)
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine("postgresql+psycopg://user:pass@localhost/db")
SessionFactory = sessionmaker(engine, expire_on_commit=False)
with SessionFactory() as session:
# auto-closed on exit
pass
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
async_engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db",
pool_size=5, max_overflow=10, pool_pre_ping=True,
)
AsyncSessionFactory = async_sessionmaker(
async_engine, class_=AsyncSession, expire_on_commit=False,
)
async with AsyncSessionFactory() as session:
result = await session.execute(select(User))
users = result.scalars().all()
from sqlalchemy import select, and_, or_, func
from sqlalchemy.orm import selectinload
# Basic select
stmt = select(User).where(User.name == "alice")
# Multiple conditions (AND)
stmt = select(User).where(and_(User.active == True, User.age > 18))
# IN clause
stmt = select(User).where(User.id.in_([1, 2, 3]))
# Join with eager loading
stmt = select(User).options(selectinload(User.posts)).where(User.active == True)
# Aggregation
stmt = select(func.count()).select_from(User).where(User.active == True)
<workflow>
| Need | Pattern | Key Import |
|---|---|---|
| Define a model | DeclarativeBase + mapped_column() | sqlalchemy.orm |
| Sync database access | sessionmaker factory | sqlalchemy.orm |
| Async database access | async_sessionmaker factory | sqlalchemy.ext.asyncio |
| Query data | select() + where() chain | sqlalchemy |
| Eager load relations | selectinload() / joinedload() | sqlalchemy.orm |
| Schema migration | Alembic autogenerate | alembic |
Mapped[] + mapped_column() -- never Column()with / async with) for session lifecycleselect() -- never session.query()selectinload() or raiseload("*") in async contextsRun through the validation checkpoint below before considering the work complete.
</workflow> <guardrails>select(User).where(...) not session.query(User).filter(...)mapped_column(): never Column() for ORM modelsMapped[int], Mapped[Optional[str]] -- no untyped columnssessionmaker / async_sessionmaker: never raw Session() calls in applicationsexpire_on_commit=False in async session factories to avoid lazy-load errorsselectinload() in async contexts -- lazy loading triggers MissingGreenlet errorsback_populates over backref for explicit bidirectional relationshipsBefore delivering SQLAlchemy code, verify:
Mapped[] + mapped_column() (no legacy Column())select() style (no session.query())expire_on_commit=False for asyncselectinload, joinedload)String(100), not bare Stringasyncpg not psycopg for async)Task: "Create a User model with posts relationship, async session setup, and a query to fetch active users with their posts."
from __future__ import annotations
from datetime import datetime
from typing import Optional
from sqlalchemy import ForeignKey, String, Text, DateTime, func, select
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, selectinload
# --- Models ---
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100))
email: Mapped[str] = mapped_column(String(255), unique=True)
active: Mapped[bool] = mapped_column(default=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now()
)
posts: Mapped[list[Post]] = relationship(back_populates="author")
class Post(Base):
__tablename__ = "posts"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(200))
body: Mapped[Optional[str]] = mapped_column(Text)
author_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
author: Mapped[User] = relationship(back_populates="posts")
# --- Async Engine & Session ---
async_engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost:5432/mydb",
pool_size=5, max_overflow=10, pool_pre_ping=True,
)
AsyncSessionFactory = async_sessionmaker(
async_engine, class_=AsyncSession, expire_on_commit=False,
)
# --- Query ---
async def get_active_users_with_posts() -> list[User]:
async with AsyncSessionFactory() as session:
stmt = (
select(User)
.options(selectinload(User.posts))
.where(User.active == True)
.order_by(User.name)
)
result = await session.execute(stmt)
return list(result.scalars().all())
</example>
For detailed guides and code examples, refer to the following documents in references/:
Mapped[] annotations, mapped_column(), mixins, inheritance, hybrid properties.relationship() typing, one-to-many, many-to-many, loading strategies, cascades, self-referential.select() statements, where clauses, joins, aggregations, subqueries, CTEs, bulk operations, result handling.create_engine(), connection URLs, pooling, events, async engines, multi-engine patterns.Session, AsyncSession, lifecycle, scoped sessions, merge, refresh, savepoints.AsyncSession patterns, driver notes, lazy-loading pitfalls.