Reference Guide Detailed deployment notes with production context and concrete examples.

Flask Migrations Not Applied (Fix Guide)

If you're seeing missing tables, column errors, or deployment failures because Flask database migrations were not applied, this guide shows you how to diagnose and fix it step-by-step. The goal is to confirm the migration state, apply the correct revision, and verify the production database matches the running code.

Quick Fix / Quick Setup

Run migration commands on the server using the same virtualenv, Flask app entrypoint, and database configuration used by the production service.

bash
# Activate the correct environment
source /path/to/venv/bin/activate

# Load production environment variables if needed
export FLASK_APP=wsgi.py
export FLASK_ENV=production
export DATABASE_URL='postgresql://user:pass@host/dbname'

# Check current revision
flask db current

# See unapplied migrations
flask db heads
flask db history

# Apply pending migrations
flask db upgrade

# Verify schema state
flask db current

# If using systemd, restart the app after success
sudo systemctl restart gunicorn
sudo systemctl status gunicorn --no-pager

Most migration issues happen because commands are run in the wrong environment or against the wrong database.

What’s Happening

Flask-Migrate and Alembic track schema revisions in the database with an alembic_version table. If new migration files exist in your codebase but flask db upgrade was skipped, failed, or targeted a different database, your app runs against an outdated schema. This usually appears as missing table errors, undefined column errors, duplicate column errors, or app startup failures after deployment.

Step-by-Step Guide

  1. Confirm the production app is using the expected database
    Check the environment variables used by systemd, Docker, or your shell.
    bash
    echo $FLASK_APP
    echo $DATABASE_URL
    

    If you use systemd, inspect the service definition:
    bash
    sudo systemctl cat gunicorn
    

    Look for:
    • Environment=
    • EnvironmentFile=
    • the app working directory
    • the Python executable path
  2. Activate the same Python environment used by the app
    A mismatched virtualenv can point Flask CLI at the wrong dependencies or app module.
    bash
    source /path/to/venv/bin/activate
    which python
    which flask
    
  3. Verify Flask CLI can load the application
    If the app does not load, migration commands may fail or use the wrong context.
    bash
    flask routes
    

    Or verify the app config directly:
    bash
    python -c "from yourapp import create_app; app=create_app(); print(app.config.get('SQLALCHEMY_DATABASE_URI'))"
    

    If this fails, fix import errors, missing environment variables, or application factory issues first.
  4. Check the current migration state
    Compare the current database revision to the latest migration head.
    bash
    flask db current
    flask db heads
    flask db history
    

    Expected result:
    • flask db current should report the current revision in the live database
    • flask db heads should report the latest available revision in code
    • if they differ, migrations are pending or history is inconsistent
  5. Apply pending migrations
    Run the upgrade against the production database.
    bash
    flask db upgrade
    

    Then verify:
    bash
    flask db current
    flask db heads
    

    The current revision should match the latest head.
  6. Inspect failed migrations if upgrade does not complete
    If flask db upgrade fails, inspect the referenced revision file under migrations/versions/.
    Common failure patterns:
    • duplicate table or column
    • missing dependency object
    • manual schema drift
    • invalid SQL
    • insufficient DB permissions

    Do not generate new migrations in production to work around this. Fix the existing migration path.
  7. Validate the database schema directly
    For PostgreSQL, check the revision table and actual schema objects.
    bash
    psql "$DATABASE_URL" -c "select * from alembic_version;"
    psql "$DATABASE_URL" -c "\dt"
    psql "$DATABASE_URL" -c "\d your_table_name"
    

    Confirm that expected tables, indexes, and columns now exist.
  8. Restart application processes after the schema update
    If your deployment flow requires a reload, restart Gunicorn or your container only after migrations succeed.
    bash
    sudo systemctl restart gunicorn
    sudo systemctl status gunicorn --no-pager
    
  9. Test the failing path
    Verify the endpoint, job, or startup path that previously failed.
    Check for:
    • no SQLAlchemy schema errors
    • no undefined column errors
    • no missing relation errors
    • successful app startup
  10. Prevent the issue in future deploys
    Add schema upgrades to the deployment sequence before service reload.
    Example deployment order:
    bash
    git pull
    source /path/to/venv/bin/activate
    pip install -r requirements.txt
    flask db upgrade
    sudo systemctl restart gunicorn
    

    If your production service fails after migration changes, also review Flask Gunicorn Service Failed to Start.

Common Causes

  • Wrong DATABASE_URL or environment variables loaded on the server → Migrations are applied to a different database than the one Gunicorn uses → Check systemd or Docker environment and compare it to live app config.
  • Deployment skipped flask db upgrade → New code expects schema changes that were never applied → Run flask db upgrade as part of the release process before restarting the app.
  • Wrong virtualenv or Flask app entrypoint → Flask CLI cannot discover the correct app or migration context → Activate the production virtualenv and set FLASK_APP correctly.
  • Migration files were not deployed → Database cannot reach the expected head revision → Deploy the missing migrations/versions files and rerun the upgrade.
  • Multiple migration heads or branch divergence → Alembic cannot determine a single upgrade path → Create and deploy a merge migration.
  • Manual database changes created schema drift → Migration fails with duplicate object or dependency errors → Compare the actual schema to migration logic and reconcile the drift before retrying.
  • Insufficient database permissions → Migration cannot create, alter, or drop objects → Grant the required privileges to the production database user.
  • Application starts before migrations complete → Requests hit the old schema during rollout → Run migrations first, then restart or reload application processes.

Debugging Section

Use these commands to inspect the environment, migration state, service health, and live database.

bash
source /path/to/venv/bin/activate
echo $FLASK_APP
echo $DATABASE_URL
flask routes
flask db current
flask db heads
flask db history
flask db upgrade
python -c "from yourapp import create_app; app=create_app(); print(app.config.get('SQLALCHEMY_DATABASE_URI'))"
sudo systemctl status gunicorn --no-pager
sudo journalctl -u gunicorn -n 100 --no-pager
sudo journalctl -u nginx -n 50 --no-pager
psql "$DATABASE_URL" -c "select * from alembic_version;"
psql "$DATABASE_URL" -c "\dt"
psql "$DATABASE_URL" -c "\d your_table_name"

What to look for:

  • flask db current returns no revision or the wrong revision
  • flask db heads shows a newer revision than current
  • flask db upgrade fails on a specific migration file
  • journalctl -u gunicorn shows startup failures tied to missing columns or tables
  • alembic_version points to a revision not present in the deployed code
  • the production schema does not match the code assumptions

If Nginx is healthy but Gunicorn is failing due to schema errors, see Fix Flask 502 Bad Gateway (Step-by-Step Guide).

Checklist

  • Production commands were run in the correct virtualenv or container
  • FLASK_APP and database environment variables point to the production app
  • flask db current matches the latest migration head
  • Required tables and columns exist in the production database
  • Gunicorn or app containers were restarted after the migration
  • The failing endpoint or startup path now works without SQL or schema errors

For a broader deployment validation pass, use Flask Production Checklist (Everything You Must Do).

FAQ

Q: Should I run flask db migrate on the production server?
No. Create and review migrations before deployment, then run flask db upgrade in production.

Q: Why does the app still fail after flask db upgrade succeeds?
The service may still be using old code, old environment variables, cached workers, or a different database connection. Verify config and restart the app.

Q: What does multiple heads mean in Alembic?
It means migration history branched. You need to create a merge migration so there is a single upgrade path.

Q: Can I edit a migration file after it has already been applied in production?
Avoid editing applied migrations. Create a new corrective migration instead.

Q: How do I confirm the live database matches the migration state?
Check flask db current, inspect alembic_version directly, and verify the expected tables or columns exist in the production database.

Final Takeaway

Most Flask migration failures in production come from running upgrade commands in the wrong environment or against the wrong database. Confirm the app context, inspect the current Alembic revision, apply the pending upgrade, and verify the live schema before reloading the service.