How to Resolve Django Migration Sequence Conflicts in Team Development

Table of Contents

Introduction

Django migrations are essential for database schema management, but they can become problematic when multiple engineers work on the same application simultaneously. One common issue is migration sequence conflicts — when two engineers create migrations with the same sequence number, causing Django to throw exceptions during deployment.

This guide shows you how to resolve these conflicts safely, without affecting production data or breaking your deployment pipeline.

Understanding the Problem

Migration sequence conflicts occur when:

  1. Engineer A creates migration 0002_some_migrations.py and pushes to production
  2. Engineer B (working locally) creates migration 0002_some_other_migrations.py
  3. When Engineer B pulls the latest changes, Django encounters conflicting sequence numbers
  4. Django throws an exception because it can't determine the correct migration order

The key constraint: You cannot modify or remove the production migration because it's already applied and users depend on it.

Why Squashing Won't Help

Migration squashing is a Django feature that combines multiple migration files into one. However, it won’t solve this specific problem because:

  • Production migration is live: Squashing would require removing a live migration, which isn't feasible.
  • Data dependencies: Squashing might roll back schema changes or data, risking data loss.
  • Deployment timeline: You can't squash and coordinate across environments quickly during an active issue.
  • Team coordination: Squashing resets migration state for everyone — highly disruptive in active development.

Use squashing for long-term cleanup, not for resolving active sequence conflicts.

Step-by-Step Solution

Step 1: Revert Your Local Migration

python manage.py migrate app_name 0001_initial

This rolls back your local conflicting migration.

Step 2: Remove Your Local Migration File

rm app_name/migrations/0002_some_other_migrations.py

Step 3: Keep the Production Migration

Ensure the 0002_some_migrations.py from the main branch is kept — it's already applied in production.

Step 4: Create a New Migration

python manage.py makemigrations app_name

This will generate 0003_some_other_migrations.py with the correct sequence number.

Step 5: Apply the New Migration

python manage.py migrate app_name

Step 6: Push Your Changes

git add .
git commit -m "Recreate migration with correct sequence number"
git push origin main

Prevention Strategies

1. Coordinate Migration Creation

  • Communicate with team before creating migrations
  • Use feature branches and pull requests
  • Add clear migration prefixes if needed

2. Add Migration Checks in CI

# .github/workflows/migration-test.yml
- name: Test Migrations
  run: |
    python manage.py makemigrations --check
    python manage.py migrate --plan

3. Periodic Squashing

python manage.py squashmigrations app_name 0001 0010

This helps reduce migration clutter over time.

4. Always Backup Before Migrations

pg_dump database_name > backup_$(date +%Y%m%d_%H%M%S).sql

Never run migrations on production without a backup.

Conclusion

Migration sequence conflicts are inevitable in active teams. But by following a clear recovery process:

  • Production stability is maintained
  • No data is lost
  • Your team keeps moving forward
  • Migration history stays clean and traceable

Pro tip: Test all migrations in a staging environment before promoting to production.