Introduction
Django migration conflicts occur when two developers create migrations from the same base migration on different branches. When both branches are merged, Django detects multiple leaf nodes (migration files with no children) and raises CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph. This is one of the most common collaboration issues in Django projects because makemigrations generates migration numbers based on what exists locally, not what is in the main branch. Without resolution, Django cannot determine migration order and refuses to run migrations.
Symptoms
``` CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph: (0023_add_user_profile, 0023_add_order_status in myapp).
To fix them run 'python manage.py makemigrations --merge' ```
Or:
django.db.migrations.exceptions.InconsistentMigrationHistory:
Migration admin.0001_initial is applied before its dependency myapp.0001_initialCommon Causes
- Concurrent development on branches: Two branches create migrations from the same base
- Squashed migration not applied: Squashed migration exists but old migrations still applied
- Manual migration edits: Migration files edited after creation, breaking dependency chain
- Deleted migration files: Migration files deleted from disk but not from database
- Third-party app migration conflicts: Upgraded package with migration that conflicts
- Reverted migration: Migrate --fake applied incorrectly, migration history diverged
Step-by-Step Fix
Step 1: Identify conflicting migrations
```bash # Show migration conflicts python manage.py showmigrations myapp
# Output shows branching: # myapp # [X] 0020_auto_20260101_1234 # [X] 0021_add_field_x # |- [X] 0022a_add_profile <- branch A # |- [X] 0022b_add_status <- branch B (conflict!) ```
Step 2: Create a merge migration
```bash # Django can auto-generate a merge migration python manage.py makemigrations --merge myapp
# This creates: myapp/migrations/0023_merge_20260409_1234.py # Which has dependencies on both 0022a and 0022b ```
Step 3: Apply the merged migration
```bash # Verify the merge migration looks correct cat myapp/migrations/0023_merge_*.py
# Apply migrations python manage.py migrate myapp
# Verify clean state python manage.py showmigrations myapp # Should show linear chain with no branching ```
Step 4: Resolve complex conflicts manually
```python # If auto-merge fails, create manual merge migration: # myapp/migrations/0023_merge_manual.py
from django.db import migrations
class Migration(migrations.Migration): dependencies = [ ('myapp', '0022a_add_profile'), ('myapp', '0022b_add_status'), ]
operations = [ # Add any operations needed to reconcile both branches # Often this is empty if branches modified different models ] ```
Prevention
- Run
python manage.py makemigrations --checkin CI to catch uncommitted migrations - Rebase feature branches on main before running makemigrations to get latest migration
- Use a single migration generation step in the deployment pipeline
- Add pre-commit hooks that check for migration conflicts before merging PRs
- Document migration conflict resolution in your team's contributing guide
- For large teams, consider using a migration number assignment service
- Never edit migration files that have been deployed -- create new migrations instead