pip install alembic★Pulls in SQLAlchemy. Gives you thealembicCLI.alembic init alembic★Scaffolds the migration env once per project: createsalembic.ini, thealembic/dir withenv.py, and an emptyversions/folder for scripts.alembic init -t async alembicasyncUse the async template when your app runs onasyncio(asyncpg, aiosqlite) —env.pyis generated with an async engine.alembic -c path/to/alembic.ini <cmd>-cpoints at a non-default config;-nselects a named section for multi-DB setups.
# alembic.ini sqlalchemy.url = postgresql+psycopg://user:pass@host/db★The DB connection. Fine for local dev — but for apps, don't hardcode secrets here (see next).# env.py — set the URL from your app/settings config.set_main_option("sqlalchemy.url", os.environ["DATABASE_URL"])★Override the ini value at runtime so migrations use the same env-driven URL as your app.# env.py — the key line for autogenerate from myapp.models import Base target_metadata = Base.metadata★Autogenerate compares thisMetaDatato the DB. For SQLModel useSQLModel.metadata. Import every model module so all tables are registered.context.configure(..., compare_type=True, compare_server_default=True)Off by default. Turn on so autogenerate also detects column type and server-default changes.
alembic revision --autogenerate -m "add users table"★The everyday command. Diffstarget_metadatavs the DB and writes a script inversions/. Always open and review it before applying.alembic revision -m "custom change"Creates an empty revision to hand-write — for data migrations or anything autogenerate can't infer.# versions/xxxx_add_users_table.py revision = "a1b2c3d4" down_revision = "9f8e7d6c" # parent; None for the first def upgrade(): ... def downgrade(): ...★Each script is a node in a linked list.down_revisionchains it to its parent (a GUID, not a sequence number — so branches merge cleanly).