一键导入
sqlalchemy-schema-migration-gotcha
Use when adding columns to existing SQLAlchemy/SQLModel models, troubleshooting schema drift, or setting up Alembic with async engines and externally-managed tables
菜单
Use when adding columns to existing SQLAlchemy/SQLModel models, troubleshooting schema drift, or setting up Alembic with async engines and externally-managed tables
Universal coding standards, best practices, and patterns. Use when developing in any language — triggers on TypeScript, JavaScript, React, Node.js, Python, Nix, ruff, pyright, pytest, uv, flake.nix, justfile, just, recipes, and general code quality topics.
Use when writing git commit messages, reviewing commits, or setting up commit conventions. Triggers on commit, git commit, commit message, changelog, semantic versioning.
A formal evaluation framework for Claude Code sessions, implementing eval-driven development (EDD) principles.
Audit NixOS impermanence configuration — find files on root filesystem not covered by persistence declarations. Use when the user wants to check for untracked files, audit impermanence, or runs /impermanence-audit.
Docker-in-Docker with network_mode host for multi-node simulation
Use when implementing LangGraph workflows that need to pause for user input or external confirmation before continuing execution
| name | sqlalchemy-schema-migration-gotcha |
| description | Use when adding columns to existing SQLAlchemy/SQLModel models, troubleshooting schema drift, or setting up Alembic with async engines and externally-managed tables |
Base.metadata.create_all(engine) only creates new tables. It does NOT add new columns to existing tables.
Adding a new field to a SQLAlchemy model and restarting the app will cause runtime errors:
sqlalchemy.exc.ProgrammingError: column "auto_select" of relation "sessions" does not exist
create_all() checks if a table exists by name. If the table already exists, it skips it entirely — even if the model has new columns that the table lacks.
This project uses Alembic for proper schema migrations (set up in rca-agent/):
# Generate migration after model changes
just db-revision "add auto_select to sessions"
# Apply migrations
just db-upgrade
# Rollback one step
just db-downgrade
# View history
just db-history
When using Alembic with asyncpg/psycopg async engines, env.py must use async_engine_from_config and connection.run_sync():
async def run_async_migrations() -> None:
connectable = async_engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
async with connectable.connect() as connection:
await connection.run_sync(do_run_migrations)
await connectable.dispose()
When other systems (e.g. LangGraph checkpointer) create tables in the same database, use include_name to prevent Alembic autogenerate from dropping them:
EXCLUDED_TABLES = {"checkpoint_blobs", "checkpoint_migrations", ...}
def include_name(name, type_, parent_names):
return not (type_ == "table" and name in EXCLUDED_TABLES)
# Pass to context.configure()
context.configure(connection=connection, target_metadata=metadata, include_name=include_name)
Use asyncio.to_thread to run Alembic's synchronous upgrade from an async context:
alembic_cfg = AlembicConfig(str(Path(__file__).resolve().parents[3] / "alembic.ini"))
await asyncio.to_thread(command.upgrade, alembic_cfg, "head")
When you add a column to an existing SQLAlchemy/SQLModel model:
just db-revision "description" to generate a migrationjust db-upgrade to apply itcreate_all() will update existing tables