DEV Community

Cover image for Squashing is so much fun, if you know how to do that
Maksym
Maksym

Posted on

Squashing is so much fun, if you know how to do that

During development I often get frustrated by how frequently I need to change the database schema and generate new migrations, which quickly clutters the project and slows things down; my staging environment adds another twist since it runs entirely in Docker without Python installed on the host, giving me more free space and isolation but also making it harder to manage migrations directly, so this guide is written to help developers like me — and you — keep migrations clean, squash them when needed, and stay sane while juggling schema changes in containerized setups.

🧩 Why squashing?

Squashing migrations reduces clutter. Instead of having many small migration files, you combine them into one. This makes your project cleaner and faster to migrate on fresh databases.


📖 Step‑by‑Step Guide

1. Check your current migrations

Run:

python manage.py showmigrations myapp
Enter fullscreen mode Exit fullscreen mode

You’ll see something like:

[X] 0001_initial
[X] 0002_auto
[X] 0003_add_field
[X] 0004_auto
[X] 0005_auto
Enter fullscreen mode Exit fullscreen mode

The [X] means they’ve already been applied.


2. Run squashmigrations

Tell Django to squash up to the latest migration:

python manage.py squashmigrations myapp 0005
Enter fullscreen mode Exit fullscreen mode

This creates a new file, usually named:

myapp/migrations/0001_squashed_0005.py
Enter fullscreen mode Exit fullscreen mode

3. Edit the replaces list

Open the new squashed migration file. You’ll see something like:

replaces = [
    ('myapp', '0001_initial'),
    ('myapp', '0002_auto'),
    ('myapp', '0003_add_field'),
    ('myapp', '0004_auto'),
    ('myapp', '0005_auto'),
]
Enter fullscreen mode Exit fullscreen mode

Since you only want to squash 0004 and 0005, trim the list:

replaces = [
    ('myapp', '0004_auto'),
    ('myapp', '0005_auto'),
]
Enter fullscreen mode Exit fullscreen mode

4. Keep old migrations temporarily

Do not delete 0004 and 0005 yet. Commit the squashed migration alongside them. Django will treat the squashed migration as equivalent to those two.


5. Test on a fresh database

Drop your local DB and recreate it, then run:

python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Check that the squashed migration applies cleanly and the schema looks correct.


6. Clean up

Once you’re confident:

  • Delete 0004_auto.py and 0005_auto.py from your repo.
  • Keep 0001, 0002, 0003 (since they’re already applied in production).
  • Keep the new squashed migration file.

7. Push to Git

Commit the changes and push. Teammates who already applied 0004 and 0005 won’t break — Django knows the squashed migration replaces them.


🚀 Best Practices

  • Always test squashed migrations on a fresh database.
  • Never squash migrations that are already deployed unless you’re only squashing the latest ones.
  • Communicate with your team before removing old migration files.

Hopefully this article will help you in the development or extend your knowledge in field of database migrations in Django. As always if you have any thoughts, criticism or just want to clarify something, write a comment!

Top comments (0)