Database Migrations

Database migrations record schema changes such as creating tables, adding columns, changing indexes, and updating constraints. In Flask projects, the common stack is SQLAlchemy plus Flask-Migrate. Flask-Migrate uses Alembic under the hood, so model changes can become versioned migration scripts.

The goal is not only to change the database. The goal is to make schema changes reviewable, repeatable, and safe across development, testing, and production environments.

Install And Initialize

pip install Flask-Migrate

Bind the extension in your application:

from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
migrate = Migrate()

def create_app():
    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"

    db.init_app(app)
    migrate.init_app(app, db)

    return app

Create the migration directory:

flask db init

This creates migrations/. Commit this directory to Git because it contains the database version history for the project.

Basic Workflow

After changing your models, generate a migration:

flask db migrate -m "add users table"

Review the generated migration file, then apply it:

flask db upgrade

Check the current database version:

flask db current

Rollback one migration:

flask db downgrade

Example: Add A Column

Suppose the original user model has only id and email:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True, nullable=False)

Add a nickname:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True, nullable=False)
    nickname = db.Column(db.String(80), nullable=True)

Then run:

flask db migrate -m "add user nickname"
flask db upgrade

Always inspect the generated script. Autogeneration usually detects simple additions, but complex changes often need manual edits.

Team Workflow

A reliable team workflow is:

  1. Change SQLAlchemy models.
  2. Run flask db migrate -m "clear message".
  3. Review the migration script.
  4. Run flask db upgrade locally.
  5. Run tests.
  6. Commit model changes and migration files together.

After pulling the latest code, teammates can update their local database with:

flask db upgrade

Production Notes

  • Back up the database before running migrations.
  • Run the migration in a staging environment first.
  • Avoid expensive schema changes during peak traffic.
  • For large tables, split risky changes into phases: add nullable column, backfill data, then add a non-null constraint.
  • Do not rewrite old migrations that have already been shared. Create a new migration instead.

Common Problems

migrate does not detect changes

Make sure your models are imported by the Flask application. If the model module is never loaded, Alembic cannot compare model metadata with the database schema.

The generated script wants to drop a column

Do not run it blindly. Renames are often detected as "drop old column and add new column", which can lose data. Edit the migration script to perform a rename or data-preserving operation.

Database version and code are out of sync

Inspect the current state:

flask db current
flask db heads

If the database schema has already been manually updated and only the migration version is missing, you can carefully mark it:

flask db stamp head

stamp records a version without applying schema changes, so use it only when you are certain the database structure is already correct.

Summary

Treat migrations as part of your codebase. Commit model changes and migration scripts together, review scripts before applying them, and back up production databases before upgrades. This habit makes Flask database changes safer and easier to coordinate across a team.