Alembic Basics: Getting Started with Database Migrations
Alembic is a lightweight migration tool that tracks database schema changes as timestamped Python files you commit to version control. Installing Alembic and running alembic init creates a versioned migration folder, an environment configuration file, and a special metadata table in your database to track which migrations have run. Every schema change becomes a numbered revision that you can review, test, and roll back.
What Is Alembic and Why You Need It
Alembic is a database migration framework for SQLAlchemy, though it works with any SQL database. When you add a column, rename a table, or drop an index, you write (or auto-generate) a migration file. Running alembic upgrade head applies pending migrations in sequence; running alembic downgrade -1 rolls back the last one. This decouples your application code from your database schema—you deploy code and migrations independently, and each is reversible.
Most teams without a migration tool resort to manual SQL scripts or risky ad-hoc alter statements. Alembic prevents schema drift, where your production database diverges from your development environment. It also gives you a clear audit trail of who changed what and when.
Step 1: Install Alembic
Use pip to install Alembic and SQLAlchemy (the ORM engine Alembic depends on):
pip install alembic sqlalchemy
This installs the alembic command-line tool and the libraries it needs. For a specific version (e.g., for reproducible builds), pin it in requirements.txt:
alembic==2.0.6
sqlalchemy==2.0.23
Check the installation:
alembic --version
You should see output like alembic, version 2.0.6 (exact version depends on your pip packages).
Step 2: Initialize Your Migration Environment
Create a new directory for your project and initialize Alembic:
mkdir my_app
cd my_app
alembic init migrations
This creates a migrations/ folder with these key files:
migrations/env.py— Alembic's runtime configuration; defines how to connect to your databasemigrations/script.py.mako— Template for new migration filesmigrations/versions/— Folder where all migration files (numbered revisions) livealembic.ini— Project-level configuration file specifying database URL, logging, and other optionsmigrations/README— Quick reference for Alembic commands
Step 3: Configure Your Database Connection
Edit alembic.ini and set the sqlalchemy.url parameter to point to your database. For a local SQLite database:
# alembic.ini
sqlalchemy.url = sqlite:///./app.db
For PostgreSQL with a password:
sqlalchemy.url = postgresql://user:password@localhost:5432/mydb
For MySQL:
sqlalchemy.url = mysql+pymysql://user:password@localhost:3306/mydb
Alembic reads this URL on every command to know which database to talk to.
Step 4: Link Alembic to Your SQLAlchemy Models
Open migrations/env.py and add your SQLAlchemy Base metadata so Alembic can auto-detect schema changes. Near the top of the file, add:
# migrations/env.py
from app.models import Base # Import your SQLAlchemy declarative base
# ...
target_metadata = Base.metadata # Tell Alembic where your models are
Replace app.models with the actual import path to your models. The Base is your SQLAlchemy declarative base (created with Base = declarative_base() or class Base(DeclarativeBase): pass in newer SQLAlchemy).
Step 5: Create Your First Migration
Run the auto-generate command to create an initial migration from your models:
alembic revision --autogenerate -m "Initial schema"
This creates a new file in migrations/versions/ named something like 001_initial_schema.py. Open it and you'll see Python code that creates your tables:
# migrations/versions/001_initial_schema.py
def upgrade():
op.create_table('users',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(50), nullable=False),
sa.PrimaryKeyConstraint('id')
)
def downgrade():
op.drop_table('users')
The upgrade() function runs when you apply the migration; downgrade() runs when you rollback.
Step 6: Apply the Migration
Run your first migration:
alembic upgrade head
This applies all pending migrations up to head (the latest). Alembic creates a table called alembic_version in your database to track which revisions have been applied. You can check the current version:
alembic current
Output shows the hash of the latest applied migration.
Key Directory Structure
After initialization, your project looks like:
my_app/
alembic.ini
app.py
models.py
migrations/
env.py
script.py.mako
README
versions/
001_initial_schema.py
Every time you run alembic revision or alembic upgrade, Alembic talks to env.py to configure the connection and then runs the appropriate scripts.
Key Takeaways
- Alembic manages database schema versions as repeatable, reversible Python scripts stored in Git
- Install with
pip install alembic sqlalchemyand initialize withalembic init migrations - Configure your database URL in
alembic.iniand link your SQLAlchemy models inenv.py - Run
alembic revision --autogenerate -m "message"to create a new migration - Run
alembic upgrade headto apply pending migrations andalembic downgrade -1to rollback the last one - Alembic tracks which migrations have run in an
alembic_versiontable in your database
Frequently Asked Questions
What is the difference between alembic revision and alembic upgrade?
alembic revision creates a new migration file without running it. alembic upgrade applies one or more existing migrations to your database. Think of revision as "write a change script" and upgrade as "execute it on the database."
Can I use Alembic without SQLAlchemy ORM?
Yes. Alembic supports raw SQL migrations and non-ORM databases. In env.py, you disable auto-generation and write migrations by hand using the op object, which provides functions like op.execute() for arbitrary SQL. ORM-based projects benefit most from auto-detection, but Alembic is flexible.
How do I roll back to an earlier version?
Use alembic downgrade <revision> to move back to a specific revision, or alembic downgrade -1 to go back one step. Downgrade runs the downgrade() function in each migration file in reverse order. Always test rollbacks in staging before production.
What if I have an existing database without migrations?
Run alembic stamp <revision> to mark a specific revision as already applied without running it. For example, alembic stamp head marks the current schema as if all migrations had run. Then create new migrations for any future changes.