Migrations Basics
Generate and apply schema changes with makemigrations and migrate. Learn migration files, dependencies, squashing, and safe workflows.
1. Introduction
Migrations are Django's way of tracking and applying changes to your database schema. Every time you add a field, rename a model, or change a relationship, Django records that change in a migration file and applies it to the database when you run migrate.
This guide covers the full migrations workflow — creating, applying, inspecting, and safely managing migrations in both development and production.
- You should already have models defined in your app.
- Your
.venvmust be active and Django 5.2 installed.
2. The two commands you use every day
# Step 1 — generate migration files from model changes
python manage.py makemigrations
# Step 2 — apply migration files to the database
python manage.py migrate
You run these two commands every time you change a model. They are always run in this order — makemigrations first, then migrate.
makemigrations does not touch the database. It only reads your models and writes Python files that describe the change. migrate reads those files and runs the actual SQL against the database.
3. What a migration file looks like
After running makemigrations, Django creates a file inside the app's migrations/ folder. For example, after defining the Article model:
pages/
└── migrations/
├── __init__.py
└── 0001_initial.py
Open 0001_initial.py and you will see something like this:
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name='Article',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True)),
('title', models.CharField(max_length=200)),
('content', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('updated', models.DateTimeField(auto_now=True)),
],
),
]
Each migration file contains a Migration class with a list of operations. Django reads these operations and generates the SQL to run against the database. You rarely need to edit migration files by hand — but it helps to understand what is inside them.
4. Useful migration commands
Check migration status
python manage.py showmigrations
# Output example:
# pages
# [X] 0001_initial ← applied
# [ ] 0002_article_slug ← not yet applied
See the SQL without applying it
python manage.py sqlmigrate pages 0001
# Prints the raw SQL that this migration will run
Run migrations for a specific app only
python manage.py migrate pages
Roll back to a previous migration
# Roll back to just after 0001 was applied (undoes 0002 and later)
python manage.py migrate pages 0001
Check for issues without applying
python manage.py migrate --check
# Exits with a non-zero code if there are unapplied migrations
5. Making model changes safely
Every time you change a model, follow this workflow:
- Make your change in
models.py. - Run
python manage.py makemigrationsto generate the migration. - Review the generated migration file to confirm it matches what you intended.
- Run
python manage.py migrateto apply it. - Commit both
models.pyand the new migration file to Git together.
6. Migration dependencies
Each migration declares which migrations it depends on. This creates a chain — Django applies them in the correct order regardless of the file names.
class Migration(migrations.Migration):
dependencies = [
('pages', '0001_initial'),
]
When migrations span multiple apps — for example adding a ForeignKey to a model in another app — Django adds that app's migration to the dependencies automatically. You will see something like ('auth', '0001_initial') in the dependencies list.
7. Squashing migrations
Over time your app can accumulate dozens of migration files. Squashing merges a range of migrations into a single file, which speeds up fresh installations and makes the migration history easier to follow.
# Squash migrations 0001 through 0010 into one file
python manage.py squashmigrations pages 0001 0010
Django generates a new migration file that replaces the squashed range. Old migration files are kept until all environments have applied the squashed migration, then they can be safely deleted.
8. Common mistakes
Forgetting to run makemigrations after a model change
The database stays out of sync with your models. Run python manage.py check to catch this early — it warns when models and migrations are out of sync.
Deleting migration files that have already been applied
Django tracks which migrations have been applied in a django_migrations table. Deleting applied migration files confuses Django and breaks the chain. Never delete applied migrations — squash them instead.
Editing a migration after it has been applied
Once a migration is applied in any environment, treat it as read-only. Create a new migration for any further changes instead of editing the existing one.
9. Next steps
You now understand how migrations work and how to manage them safely. The final page in this category covers data migrations — how to write migrations that transform or backfill existing data using RunPython.