Django "table already exists" - When to Use migrate --fake
Django tried to create a table that already exists because django_migrations does not record the migration as applied. The schema and the migration ledger disagree - --fake/--fake-initial records history without re-running SQL, but only when the schema truly matches.
What this error means
python manage.py migrate fails creating a table/column that already exists. It happens when a database already has the schema (adopted or pre-seeded) but Django’s migration table is empty or behind.
django.db.utils.ProgrammingError: relation "orders" already exists
(running 0001_initial against a database that already has the table)Common causes
Schema exists but django_migrations is empty/behind
The database already has the tables (from another tool, a restored dump, or a prior run) while Django’s ledger does not record the migrations, so it re-runs the create.
Initial migration run against a pre-existing schema
Adopting an existing database with Django for the first time runs 0001_initial, which collides with the already-present tables.
How to fix it
Fake the initial migration when adopting a schema
When the existing schema matches the initial migration, record it as applied without running DDL.
python manage.py migrate --fake-initialFake a specific migration to align history
If a specific migration’s changes are already present, mark just that one as applied.
python manage.py migrate orders 0001 --fakePrefer a clean database in CI
- In CI, start from an empty database so
migrateapplies the full history with no fakes. - Reserve
--fake/--fake-initialfor adopting a genuinely pre-existing database. - Verify the real schema matches before faking anything.
How to prevent it
- Use empty databases in CI so no faking is needed.
- Keep
django_migrationsconsistent with the real schema. - Reserve
--fake-initialfor first-time adoption of an existing database.