HOWTO · Django

How to Roll Back a Django Database Migration

Learn how to roll back Django database migrations with migrate, inspect applied migrations with showmigrations, choose a target, and account for irreversible operations and data loss.

On this page

To undo the latest applied Django migration, run python manage.py migrate <app_label> <migration_name> and choose the migration that should remain applied, usually the one immediately before the migration you want to reverse. Django reverses migrations after that target for the named app. Use showmigrations first to check the app’s current state. Back up important data before a rollback: reversing schema operations can discard data, and some operations cannot be reversed at all.

Roll Back to a Specific Migration

Use python manage.py showmigrations <app_label> to list an app’s migrations. Applied migrations have an [X] marker; unapplied migrations have [ ]. The app label is the Django application name used in migration commands, and the migration name is the filename portion without .py.

For example, suppose blog has 0001_initial, 0002_add_author, and 0003_remove_legacy_field, and all three are applied. To undo only 0003_remove_legacy_field, target 0002_add_author: python manage.py migrate blog 0002_add_author. The target describes the final migration state to keep, not the migration to undo. Django reverses 0003 and any later applied migrations for blog. A numeric prefix such as 0002 can identify the target, though using its full name makes the choice clear.

Run the command from the project environment where manage.py can load the right settings and database connection. Confirm the target app and database before proceeding, especially when several environments are configured.

Run this Python snippet to print a command for one app and target:

app_label = "blog"
target = "0002_add_author"
print(f"python manage.py migrate {app_label} {target}")
python manage.py migrate blog 0002_add_author

The snippet formats the command only; run the printed command from your Django project to change database state.

Roll Back All Migrations for an App

To reverse every applied migration for one app, use python manage.py migrate <app_label> zero, for example python manage.py migrate blog zero. Here zero is the target state before that app has any migrations applied. Django reverses the app’s migration history in reverse order. This does not mean “undo the latest migration,” and it can remove tables or columns and their data. Review the app’s migration list and back up the database before using this target.

To reverse several, but not all, migrations, specify an earlier migration as the target. Django works backward from the currently applied state until it reaches that target. Migrations for other apps are not selected just because they are later in the overall project history, although dependencies can affect the plan. Read Django’s planned operations before confirming a production change.

Understand Reversibility and Data Loss

Django can reverse an operation when its migration defines a reverse operation or Django can infer one. Some operations, such as deleting data with a custom Python operation that has no reverse function, cannot be reconstructed. Attempting to reverse such a migration raises IrreversibleError. Inspect the migration’s operations and the full error to identify which step lacks a reverse path; do not assume that restoring an older migration file makes its database effects reversible.

A reversible schema change can still lose data. For instance, reversing a field removal cannot restore values that were discarded when the field was removed. Before rolling back, take a database backup, check whether application writes must be paused, and consider whether a forward fix is safer. On production, rehearse the procedure against a recent backup and verify the recovery plan before changing the live database.

Git manages migration source files, while migrate changes database state. Checking out or reverting a Git commit does not itself roll back a database. Restoring migration files independently can also leave the code and recorded database history inconsistent, so use Django’s migration commands for the database operation and coordinate any code recovery separately.

Verify the Database State

After the command finishes, run python manage.py showmigrations <app_label> again. Confirm that the intended target and earlier migrations show [X], and migrations that were reversed show [ ]. This reports Django’s recorded migration state; it does not verify every application-level data expectation or prove that the schema and data are healthy. Check the affected application behavior and, when needed, inspect the database or run project-specific checks.

If the markers do not match the intended target, stop before issuing another rollback. Confirm that you are connected to the intended database, review the command output and migration dependencies, then decide on the next migration operation based on the actual recorded state.