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.
# 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
- Confirm the production app is using the expected database
Check the environment variables used by systemd, Docker, or your shell.bashecho $FLASK_APP echo $DATABASE_URL
If you use systemd, inspect the service definition:bashsudo systemctl cat gunicorn
Look for:Environment=EnvironmentFile=- the app working directory
- the Python executable path
- Activate the same Python environment used by the app
A mismatched virtualenv can point Flask CLI at the wrong dependencies or app module.bashsource /path/to/venv/bin/activate which python which flask - Verify Flask CLI can load the application
If the app does not load, migration commands may fail or use the wrong context.bashflask routes
Or verify the app config directly:bashpython -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. - Check the current migration state
Compare the current database revision to the latest migration head.bashflask db current flask db heads flask db history
Expected result:flask db currentshould report the current revision in the live databaseflask db headsshould report the latest available revision in code- if they differ, migrations are pending or history is inconsistent
- Apply pending migrations
Run the upgrade against the production database.bashflask db upgrade
Then verify:bashflask db current flask db heads
The current revision should match the latest head. - Inspect failed migrations if upgrade does not complete
Ifflask db upgradefails, inspect the referenced revision file undermigrations/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. - Validate the database schema directly
For PostgreSQL, check the revision table and actual schema objects.bashpsql "$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. - Restart application processes after the schema update
If your deployment flow requires a reload, restart Gunicorn or your container only after migrations succeed.bashsudo systemctl restart gunicorn sudo systemctl status gunicorn --no-pager - 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
- Prevent the issue in future deploys
Add schema upgrades to the deployment sequence before service reload.
Example deployment order:bashgit 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_URLor 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 → Runflask db upgradeas 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_APPcorrectly. - Migration files were not deployed → Database cannot reach the expected head revision → Deploy the missing
migrations/versionsfiles 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.
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 currentreturns no revision or the wrong revisionflask db headsshows a newer revision thancurrentflask db upgradefails on a specific migration filejournalctl -u gunicornshows startup failures tied to missing columns or tablesalembic_versionpoints 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_APPand database environment variables point to the production app -
flask db currentmatches 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).
Related Guides
- Deploy Flask with Nginx + Gunicorn (Step-by-Step Guide)
- Flask Gunicorn Service Failed to Start
- Fix Flask 502 Bad Gateway (Step-by-Step Guide)
- 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.