Guides / How to roll back a Django deploy (and bad migrations)
How to roll back a Django deploy (and bad migrations)
A deploy went wrong and you need to go back. Rolling back Django code is easy. Rolling back the database is where people get hurt, because migrations don't undo themselves when you redeploy old code. This guide covers both halves, in the order to do them.
What it means
A rollback has two independent parts: the code (and its settings) and the database schema. Redeploying the previous version fixes the code. If the bad release also ran a migration, the old code now runs against a newer schema, and whether that works depends on what the migration did.
Why it goes wrong
- There is no release history. You deploy by pulling
mainon a server, so "the previous version" is whatever you can reconstruct from git. - The old code can't run on the new schema. The migration dropped or renamed a column the old code still reads.
- The migration can't be reversed. A
RunPythonwithout a reverse function, or a data change that lost information. - The settings changed too. The release also needed a new environment variable, and removing it breaks the old code.
The fix
1. Roll back the code
Never rewrite history on main. Revert the bad change, or redeploy a known-good tag:
git revert --no-edit <bad-commit> # or: git revert -m 1 <merge-commit>
git push
# or deploy an earlier tag / image directly:
git checkout v1.4.2
2. Decide whether the database needs to go back
Often it doesn't. If the migration only added a nullable column or a new table, the old code ignores it and runs fine. Leave the schema alone. If the migration removed or renamed something the old code uses, reverse it:
python manage.py showmigrations myapp
python manage.py sqlmigrate myapp 0013 --backwards # review the SQL first
python manage.py migrate myapp 0012 # go back to just before 0013
Run the reverse migration with the new code still present (the migration file for 0013 must exist), and only then switch to the old code. Take a database backup or snapshot before you do.
3. When Django says a migration is irreversible
django.db.migrations.exceptions.IrreversibleError means a RunPython or RunSQL has no reverse. Prevent it when you write the migration:
from django.db import migrations
def forwards(apps, schema_editor):
...
class Migration(migrations.Migration):
dependencies = [("myapp", "0012_previous")]
operations = [
migrations.RunPython(forwards, migrations.RunPython.noop), # reversible, does nothing on the way back
]
If it is already deployed, you restore from a backup, or write the reverse by hand as a new migration. There is no shortcut.
Making it stick in production
- Keep numbered, immutable releases. Tag every deploy, or keep the previous image, so going back is one command and not an investigation.
- Make migrations backward compatible. Ship in two steps: first add the new column and keep writing the old one; remove the old column in a later release, after the code that used it is gone. Then a code rollback never needs a schema rollback.
- Back up before migrating. A snapshot taken right before
migrateturns an irreversible mistake into an inconvenience. - Roll back settings with the code. Keep environment changes in the same release as the code that needs them.
- Rehearse it. Once, on staging: deploy, migrate, roll back. You'll find the irreversible migration before it matters.
See also unapplied migrations in production for the opposite problem: code that is ahead of the schema.
Or skip it
Django Cloud saves every deploy as a numbered release you can roll back to in one click, or with djangocloud rollback. It brings back that release's settings, and warns you when an older release would run against a newer database.
pip install djangocloud-cli
djangocloud deploy
Free plans are available for students, AWS Activate startups, open-source, non-profit and research projects. See how Django Cloud compares with other ways to host Django.
Django is a registered trademark of the Django Software Foundation. Django Cloud is not affiliated with or endorsed by it. Found a mistake in this guide? Tell us and we will fix it.