Autogenerated migration files touching many tables are not production-safe by default

Let’s say I add a new field to my abstract base class that I use in half the models in my project. I generate migrations. Inside a given app, that will generate a single migration file like:

- add new_field to A
- add new_field to B
- add new_field to C
- add new_field to D
- add new_field to E
...

Migrations are atomic by default, which is great of course. But in this case we just made a migration file that is going to get a lot of locks. In practice this often means that (unless you got really lucky with the ordering) your migration is going to deadlock in any running production system.

We want generated migrations to be safe by default, and having them be atomic lets things like migration rollbacks “just work”. So my idea is simple: try to generate one file per table when generating migrations.

This would mean a lot of files, but Django migration performance issues are due to operation count, not file count. But because these migrations would still be atomic, issues would be cleanly rolled back. And failures would be a bit easier to grok.

I know of setting atomic = False, but it would be great to have the default from makemigrations not make me even have to consider that.

Replies to some scarecrows:

  • “you shouldn’t have 100 models in your app” yeah. Every big Django app has that one app.
  • “You should have a maintence window”: many people run zero-downtime Django in practice. It’s good that it works like this! It is a good property of a system running on the internet. Having maintenance windows makes things “easier” (debatable: if you can only deploy in certain time windows, what if a bug shows up?), but it has its costs