Data & Integrity

Schema Versioning & Migrations

Advanced

The database schema changes while the system is live and holding real customer data. An old version of the code may still be running next to the new one. Migrations let you change a live system safely. They must be versioned, ordered, reversible in intent, and safe to run on production-sized data.

A migration is code, and it is some of the most important code you will write. It runs once, against data you cannot replace, often under deployment pressure. Treat every schema change as a versioned, reviewed migration. By default it should be forward-only. Test it against realistic data. Design it so a deploy can never break either the old or the new application version.

We use Dapper, not an ORM that migrates from models. So our schema changes are explicit SQL migrations in source control. This is an advantage, because the change is exactly what gets reviewed. But it means the care is entirely on us. Nothing generates or checks these migrations for free.

Version every change

Deploy without downtime or data loss

Breaking rename in one step EXEC sp_rename 'Customers.Surname', 'LastName';

The moment this runs, every still-deployed instance of the old code that reads Surname breaks. A rename looks like a small change, but it is a breaking one.

Expand and contract across releases -- release 1: add the new column, backfill it, dual-write in the app
ALTER TABLE Customers ADD LastName nvarchar(200) NULL;
UPDATE Customers SET LastName = Surname WHERE LastName IS NULL;
-- release 2 (after every instance uses LastName): drop Surname

At no point does a running app version need a column the database does not have. Rollback stays safe throughout.

Self-review checklist

Why it matters: A bad migration is especially dangerous. It runs against the one copy of data that matters, often cannot be cleanly undone, and can take the whole platform down during a deploy. Versioned, backward-compatible, well-tested migrations turn a schema change into a routine, reversible step.