Database Migrations
Reviewed & published by Brayan K
A database migration is a versioned, repeatable change to your schema that transforms an existing database to match your updated models without losing data, and Flask-Migrate gives you simple commands to generate and apply them.
Part of the free Flask course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
In this lesson you'll set up Flask-Migrate, initialize a migration repository, and generate and apply your first migration with the flask db commands.
What You'll Learn in This Lesson
- What a migration is and why create_all is not enough
- How to set up Flask-Migrate
- Initializing a repo with flask db init
- Generating a migration with flask db migrate
- Applying changes with flask db upgrade
- Rolling back with flask db downgrade
1 Why Migrations Exist
A migration is a versioned schema change. When you add a column to a model, the existing database still has the old shape. A migration records the exact change so the database can catch up without losing its rows.
db.create_all() only creates tables that do not yet exist — it never alters a table that is already there. To add a column to a populated table you need a migration that issues the right ALTER while preserving data.
- Versioning: every schema change is a numbered script
- Safety: changes apply without dropping existing data
- Reversibility: you can downgrade to undo a change
- Teamwork: everyone applies the same changes in order
2 Setting Up Flask-Migrate
You wire Flask-Migrate into your app by creating a Migrate object bound to both the app and the db. That one line unlocks the flask db command group.
# app.py — enable migrations
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db = SQLAlchemy(app)
# Bind Flask-Migrate to the app and the database.
# This registers the "flask db" command group.
migrate = Migrate(app, db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), nullable=False)
print("Migrate is ready. Use the 'flask db' commands in your terminal.")
# ✅ Expected output:
# Migrate is ready. Use the 'flask db' commands in your terminal.With Migrate(app, db) in place, your terminal now understands commands like flask db init. The migration tooling runs from the command line, not from Python.
3 The Migration Workflow
The workflow has three terminal commands. Run flask db init once to create a migrations/ folder. After that, every time you change a model you run flask db migrate to generate a script, then flask db upgrade to apply it.
# Run these in your terminal (not the Python shell):
# 1. One-time: create the migrations/ folder
flask db init
# 2. Generate a migration after changing a model
flask db migrate -m "add email column to user"
# 3. Apply the migration to the database
flask db upgrade
# To undo the most recent migration:
flask db downgradeThe Python editor below shows the model change that would trigger a migration — adding an email column:
# app.py — a model change that needs a migration
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), nullable=False)
# New column added below. After saving this file you would run:
# flask db migrate -m "add email"
# flask db upgrade
email = db.Column(db.String(120))
print("Model now has columns:", [c.name for c in User.__table__.columns])
# ✅ Expected output:
# Model now has columns: ['id', 'username', 'email']🔬 The flask db Commands
| Command | What it does |
|---|---|
| flask db init | Creates the migrations/ folder (run once) |
| flask db migrate | Generates a script from model changes |
| flask db upgrade | Applies pending migrations to the database |
| flask db downgrade | Reverts the most recent migration |
🎯 Your Turn: Fill in the Blanks
Complete the setup below. Replace each ___ so it imports and binds Flask-Migrate to a model with a new column.
# 🎯 YOUR TURN: replace each ___ to enable migrations
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import ___ # import the Migrate class
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db = SQLAlchemy(app)
migrate = ___(app, db) # bind Migrate to app and db
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
price = db.Column(db.___) # add a Float column
# After saving, you would run in the terminal:
# flask db migrate -m "add price"
# flask db ___ # apply the migration
print("Columns:", [c.name for c in Product.__table__.columns])Common Errors & Quick Reference
❌ Error: No such command "db"
Flask-Migrate is not active. Make sure you installed it with pip install flask-migrate and created Migrate(app, db) in your app file.
❌ Target database is not up to date
You generated a migration but never applied it. Run flask db upgrade to bring the database in line before generating more.
| Task | Command / Code |
|---|---|
| Install | pip install flask-migrate |
| Initialize | flask db init |
| Generate | flask db migrate -m "msg" |
| Apply | flask db upgrade |
🏆 Mini Challenge: Add a Column
Plan the migration for adding a new column to an existing model.
- Set up an app with Flask-Migrate and a Post model
- Add a published boolean column to the model
- Write the two terminal commands you would run to apply it
# 🏆 Mini Challenge: a migration-ready model
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///blog.db"
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
# New column — this is the change a migration captures.
published = db.Column(db.Boolean, default=False)
# Commands to run in the terminal after this change:
# flask db migrate -m "add published to post"
# flask db upgrade
print("Post columns:", [c.name for c in Post.__table__.columns])❓ Frequently Asked Questions
Lesson complete — your schema can evolve safely!
You set up Flask-Migrate and learned the init, migrate, and upgrade workflow. Your database can now change shape without losing data.
Practice quiz
What is a database migration?
- A backup copy of the database
- A new web route
- A versioned schema change that updates the database without losing data
- A way to encrypt rows
Answer: A versioned schema change that updates the database without losing data. A migration is a versioned schema change that transforms an existing database safely.
Why isn't db.create_all() enough for an existing table?
- It only creates tables that don't exist; it never alters existing ones
- It deletes all data
- It only works on SQLite
- It requires Alembic
Answer: It only creates tables that don't exist; it never alters existing ones. create_all() makes missing tables but won't ALTER a table that already exists.
Flask-Migrate is a wrapper around which tool?
- SQLAlchemy
- Alembic
- Pytest
- Jinja2
Answer: Alembic. Flask-Migrate wraps Alembic and adds flask db commands.
How do you enable migrations in your app?
- Call db.migrate()
- Import alembic directly
- Set MIGRATE=True in config
- Create Migrate(app, db)
Answer: Create Migrate(app, db). migrate = Migrate(app, db) registers the flask db command group.
Which command creates the migrations/ folder (run once)?
- flask db init
- flask db create
- flask db start
- flask db new
Answer: flask db init. flask db init sets up the migrations/ directory one time.
Which command generates a migration script from model changes?
- flask db build
- flask db migrate
- flask db make
- flask db diff
Answer: flask db migrate. flask db migrate auto-generates a script from your model changes.
Which command applies pending migrations to the database?
- flask db apply
- flask db push
- flask db upgrade
- flask db commit
Answer: flask db upgrade. flask db upgrade applies the pending migrations.
Which command reverts the most recent migration?
- flask db revert
- flask db undo
- flask db rollback
- flask db downgrade
Answer: flask db downgrade. flask db downgrade rolls back the latest migration.
What benefit do migrations give a team?
- They speed up queries
- Everyone applies the same schema changes in order
- They remove the need for a database
- They auto-generate routes
Answer: Everyone applies the same schema changes in order. Versioned, numbered scripts let a whole team apply changes consistently.
What does 'Target database is not up to date' usually mean?
- The model has a syntax error
- You never created Migrate(app, db)
- You generated a migration but never ran flask db upgrade
- The database is corrupt
Answer: You generated a migration but never ran flask db upgrade. It means a pending migration hasn't been applied; run flask db upgrade.
Continue this course
- Previous: CRUD Operations
- Next: Error Handling & Custom Pages — Catch errors and show friendly custom 404 and 500 pages
- Quick reference: Flask cheat sheet
Frequently asked questions
What is a database migration?
A migration is a versioned change to your database schema. When you add or alter a model, a migration records exactly how to transform the existing database to match, so you never lose data or rebuild tables by hand.
Why not just use db.create_all() again?
db.create_all() only creates tables that do not yet exist; it never alters existing ones. To add a column to a populated table you need migrations, which apply incremental ALTER changes while preserving data.
What is Flask-Migrate?
Flask-Migrate is an extension that wraps Alembic to manage migrations for Flask-SQLAlchemy apps. It adds flask db commands like init, migrate, and upgrade that generate and apply schema changes.
What is the difference between migrate and upgrade?
flask db migrate generates a new migration script by comparing your models to the database. flask db upgrade actually applies that script, changing the real schema. You review the script between the two steps.