How do you manage EF Core migrations in a team and in production?
Quick Answer
Each developer generates migrations locally and commits them with the model snapshot. In production, generate an idempotent SQL script (dotnet ef migrations script --idempotent) and run it as a deployment step — not Database.Migrate() at app startup for multi-instance apps. Keep schema changes backward-compatible for zero-downtime deploys.
Developers add migrations locally and commit them along with the model snapshot file. The friction point is two people adding migrations at once — the snapshot conflicts, and you fix it by regenerating one migration on top of the other rather than merging the snapshot by hand. For production I don't run Database.Migrate on startup if there are multiple instances — I generate an idempotent SQL script and run it as an explicit deployment step so it's auditable and a DBA can look at it. And for zero-downtime I do expand-then-contract: add the new column first, migrate data and switch over in a later release, drop the old column last. Never a rename in one migration, because EF treats it as drop-and-add and the data's gone.
- Team: pull before adding a migration; if two people added migrations, the
ModelSnapshotconflicts — resolve by re-generating one on top of the other, don't hand-merge blindly. - Never edit an applied migration — add a new one.
- Production options: idempotent SQL script through the CI/CD pipeline (auditable, DBA-reviewable); a migration bundle executable; or
Migrate()on startup only for single-instance apps. - Zero downtime (expand/contract): deploy 1 adds the new nullable column and writes to both; deploy 2 backfills and switches reads; deploy 3 drops the old column. Never rename in one step — EF sees drop + add and you lose data.
- Review generated migrations for data loss (dropped columns/tables) before merging.