Beginner-Friendly: Flask-Migrate Database Migration Tutorial

Why Database Migrations Are Needed?

When developing web applications, database structures (such as table schemas and field types) may need adjustments as requirements evolve. Directly modifying database files (e.g., SQL files) can lead to data loss or version conflicts in collaborative environments. Database migration tools serve the purpose of safely altering database structures while preserving existing data, acting like “version control for your database.”

What is Flask-Migrate?

Flask-Migrate is a tool within the Flask ecosystem that simplifies database migrations. Built on top of Alembic (SQLAlchemy’s migration framework), it specifically manages database schema changes in Flask applications using SQLAlchemy. It automatically generates migration scripts and applies them to the database, eliminating the need to write SQL statements manually.

Installation and Initialization

1. Install Dependencies

First, ensure Flask and Flask-SQLAlchemy (the database ORM tool) are installed, then install Flask-Migrate:

pip install flask flask-sqlalchemy flask-migrate

2. Initialize Flask App and Database

Create a simple Flask application (e.g., app.py) and initialize the database and migration tool:

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

# Initialize Flask app
app = Flask(__name__)

# Configure database (SQLite example; replace with MySQL/PostgreSQL as needed)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  # Disable unnecessary modification tracking

# Initialize SQLAlchemy
db = SQLAlchemy(app)

# Initialize Flask-Migrate (must run after db)
migrate = Migrate(app, db)

# Define models (model changes will be demonstrated later)
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

if __name__ == '__main__':
    app.run(debug=True)

Core Migration Commands (Must-Learn!)

Flask-Migrate uses the Flask CLI for migrations. First, set the environment variable to specify your app entry point:

# Linux/Mac
export FLASK_APP=app.py  # Replace with your app's filename
# Windows (PowerShell)
$env:FLASK_APP = "app.py"

Then use the following commands:

1. Initialize Migration Environment (First Time Only)

When using Flask-Migrate for the first time, initialize a folder to store migration scripts:

flask db init

This creates a migrations folder in your project root, containing configuration files and script templates for migrations.

2. Generate Migration Scripts

After modifying a database model (e.g., adding/removing fields), generate a migration script to describe the changes:

flask db migrate -m "Description of changes"
  • -m parameter: Required, used to describe the migration purpose (e.g., "add age field to User model").
  • After execution, a Python file (e.g., xxxxxxxx_add_age_field_to_user_model.py) will appear in migrations/versions, containing the SQL statements for the model changes.

3. Apply Migrations to the Database

After generating the script, apply the SQL changes to the database:

flask db upgrade

This updates the database schema (e.g., adding the new age field to the User table).

Practical Demo: Migration Flow from 0 to 1

Suppose you need to complete the following requirements step by step:

Phase 1: Create the User Table for the First Time

  1. Initialize Migration Environment: Run flask db init to generate the migrations folder.
  2. Generate Initial Migration Script: Modify the User model and run:
   flask db migrate -m "create User table"

A script in migrations/versions will be created with SQL to create the User table.
3. Apply Migration: Run flask db upgrade to create the table in the database.

Phase 2: Modify the Model (Add a New Field)

If you need to add an age field to the User table:
1. Update the Model: Modify the User class in app.py:

   class User(db.Model):
       id = db.Column(db.Integer, primary_key=True)
       name = db.Column(db.String(80), unique=True, nullable=False)
       email = db.Column(db.String(120), unique=True, nullable=False)
       age = db.Column(db.Integer)  # New field added
  1. Generate New Migration Script: Run:
   flask db migrate -m "add age field to User"

A new script in migrations/versions will be generated with SQL to add the age column.
3. Apply the New Migration: Run flask db upgrade to add the age field to the database table.

Reverting Migrations (Optional)

If a migration causes issues or needs rollback, use the downgrade command to undo the last migration:

flask db downgrade

Note: downgrade only works if the migration script explicitly defines rollback logic (automatically generated by Flask-Migrate).

Common Issues and Beginner Tips

  1. “migrations” Folder Already Exists?
    If flask db init throws an error (e.g., “migrations already exists”), you likely ran initialization twice. Simply skip init and proceed with migrate and upgrade.

  2. Migration Script Conflicts?
    If scripts conflict during collaboration or multiple changes, check migrations/versions and manually merge SQL statements. For beginners, use version control to isolate changes.

  3. SQLite vs. MySQL/PostgreSQL?
    This example uses SQLite (no extra setup). For MySQL/PostgreSQL, update SQLALCHEMY_DATABASE_URI (e.g., mysql+pymysql://user:pass@localhost/dbname); migration logic remains identical.

Summary

Flask-Migrate follows a simple cycle: Modify Model → Generate Script → Apply to Database. Remember these 3 steps for smooth operations:

  1. Modify the Model: Update fields or table structures in db.Model.
  2. Generate Script: Use flask db migrate -m "Description" to create a migration file.
  3. Apply Changes: Run flask db upgrade to apply the changes to the database.

This approach avoids manual SQL writing, ensures data safety, and is essential for development workflows!

Xiaoye