Module 06 / Project 04 — Migrations with Alembic¶
Home: README · Module: Databases & ORM
Learn Your Way¶
| Read | Build | Watch | Test | Review | Visualize | Try |
|---|---|---|---|---|---|---|
| — | This project | — | — | Flashcards | — | — |
Focus¶
- What schema migrations are and why you need them
- Setting up Alembic in a project
- Autogenerating migrations from model changes
- Running
upgradeanddowngrade - The migration history chain
Why this project exists¶
When your application is live and has real data, you cannot just drop and recreate tables. You need a way to evolve your schema safely — adding columns, changing types, creating indexes — without losing data. Alembic is SQLAlchemy's migration tool. It tracks every schema change as a versioned script that can be applied forward or rolled back.
Setup¶
This project is more guide-driven than the others. You will run Alembic commands in your terminal alongside the Python code.
Step-by-step guide¶
Step 1: Understand the starting models¶
Look at project.py. It defines Author and Book models — the same ones from Project 02, but without a genre column on Book. We will add that column via a migration.
Step 2: Create the initial database¶
This creates library.db with the initial schema (no genre column).
Step 3: Examine the Alembic setup¶
The project already has Alembic configured:
- alembic.ini — points to the SQLite database
- alembic/env.py — imports the models so Alembic can compare them to the database
Step 4: Create the first migration¶
Now add the genre column to the Book model in project.py. Uncomment the line marked # UNCOMMENT FOR MIGRATION. Then run:
Alembic compares your models to the database and generates a migration script in alembic/versions/.
Step 5: Apply the migration¶
This runs the migration, adding the genre column to the existing database without losing any data.
Step 6: Verify¶
python -c "import sqlite3; conn = sqlite3.connect('library.db'); print([col[1] for col in conn.execute('PRAGMA table_info(books)').fetchall()])"
You should see genre in the column list.
Step 7: Rollback¶
This undoes the last migration, removing the genre column.
Expected output¶
$ python project.py
Tables created. Sample data inserted.
Books in database:
1 | The Pragmatic Programmer | David Thomas
2 | Clean Code | Robert C. Martin
3 | Fluent Python | Luciano Ramalho
$ alembic revision --autogenerate -m "add genre column to books"
Generating .../alembic/versions/xxxx_add_genre_column_to_books.py ... done
$ alembic upgrade head
Running upgrade -> xxxx, add genre column to books
$ alembic downgrade -1
Running downgrade xxxx -> , add genre column to books
Alter it¶
- Add another migration that creates an
isbncolumn (String, nullable). Apply it. - Create a data migration that sets
genre = "programming"for all existing books. - Add an index on the
genrecolumn via a migration.
Break it¶
- Manually edit the database schema (add a column by hand) without creating a migration. Now try
--autogenerate. What happens? - Delete a migration file from
alembic/versions/and try to upgrade. What error do you get? - Change a column type in the model without creating a migration. Does the app crash?
Fix it¶
- Use
alembic stamp headto tell Alembic "the database matches the current models" after a manual fix. - Create a manual migration with
alembic revision -m "fix"and write the upgrade/downgrade yourself. - Use
alembic historyto see the full chain of migrations and find where things went wrong.
Explain it¶
- What problem do migrations solve that
create_all()does not? - What is the difference between
--autogenerateand writing a migration by hand? - What does
alembic stampdo and when would you use it? - Why should migration scripts be committed to version control?
Mastery check¶
You can move on when you can:
- set up Alembic in a project with existing models,
- generate and apply a migration that adds a column,
- rollback a migration with downgrade,
- explain why create_all() is not enough for production.
Related Concepts¶
- Classes and Objects
- Collections Explained
- Files and Paths
- How Imports Work
- Quiz: Classes and Objects