Engineering/Coding Standards/C#/Entity Framework Core/Ef Migrations/

EF Core Migration Standards · EF-04

Migrations must be named descriptively and consistently · EF-04.1 · MUST

The name of each migration must be a clear indication of what a migration does, before opening the file. Always use PascalCase verb-noun names which describe the change(s) introduced in the migration.

Good Example: Descriptive migration names

20260521093000_AddColumnIsbnToBook.cs
20260521094500_CreateAuthorTable.cs
20260521100000_AddIndexOnOrderCreatedDate.cs
20260521340000_CreateStripePaymentConfigurationTable.cs

Bad Example: Vague or inconsistent migration names

20260521093000_AddData.cs
20260521094500_TC_changes.cs
20260521100000_Fix_bug_584223.cs

Never edit a migration once it has been applied to a shared environment · EF-04.2 · MUST

Never edit existing migrations once they have already been applied to a deployed database. After the migration is applied it is recorded in the __EFMigrationsHistory table, and will never be reapplied.

Good Example: Fix forward with a new migration

# Original migration AddBookIsbnColumn has already been deployed.
# The Isbn column needs a longer max length.

dotnet ef migrations add IncreaseBookIsbnLength

Bad Example: Editing an applied migration

// Editing AddBookIsbnColumn.cs after it has already been applied
// to staging. The change will never run again on environments
// where the migration is already recorded as applied.
migrationBuilder.AddColumn(
    name: "Isbn",
    table: "Books",
    type: "nvarchar(20)", // was nvarchar(13)
    nullable: false);

Keep migrations reversible · EF-04.3 · MUST

Every migration must define both Up and Down methods such that all changes can be rolled back when needed. Any operation in Up which cannot be expressed in Down is heavily discouraged.

Good Example: Reversible migration

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn(
        name: "Isbn",
        table: "Books",
        type: "nvarchar(13)",
        nullable: false,
        defaultValue: "");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
    migrationBuilder.DropColumn(
        name: "Isbn",
        table: "Books");
}

Bad Example: Non-reversible migration

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql("ALTER TABLE Books ADD Isbn nvarchar(13) NOT NULL DEFAULT '';");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
}

Keep migrations idempotent · EF-04.4 · MUST

Every migration must be able to be safely reapplied multiple times without adverse effects.

Note: This usually only applies to raw SQL inside migrations. Most MigrationBuilder commands are intrinsically guarded.

Good Example: Guarded raw SQL

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql(@"
        IF NOT EXISTS (SELECT 1 FROM [Genres] WHERE [Name] = N'Fiction')
            INSERT INTO [Genres] ([Name]) VALUES (N'Fiction');
    ");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql("DELETE FROM [Genres] WHERE [Name] = N'Fiction';");
}

Bad Example: Unguarded insert (clones data on every run)

protected override void Up(MigrationBuilder migrationBuilder)
{
    // Re-running inserts another 'Fiction' row each time — duplicates accumulate.
    migrationBuilder.Sql("INSERT INTO [Genres] ([Name]) VALUES (N'Fiction');");
}

protected override void Down(MigrationBuilder migrationBuilder)
{
}

Each migration should contain one logical change · EF-04.5 · SHOULD

Every migration must be able to be reviewed, applied and rolled back on its own. Changes cannot be reverted independently when they are contained within a migration responsible for executing other, unrelated changes.

Good Example: One change per migration

dotnet ef migrations add AddBookIsbnColumn
dotnet ef migrations add AddIndexOnOrderCreatedDate
dotnet ef migrations add RenameAuthorBioToDescription

Bad Example: Multiple unrelated changes in one migration

// Migration: MiscChanges
protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn(name: "Isbn", table: "Books", /* ... */);

    migrationBuilder.CreateIndex(name: "IX_Orders_CreatedDate", table: "Orders", /* ... */);

    migrationBuilder.RenameColumn(name: "Bio", table: "Authors", newName: "Description");
}