Skip to content

Aspnet Migrations

DodaTech 4 min read

title: ASP.NET Core Migrations — Complete Guide to EF Core Database Migrations description: 'Learn EF Core migrations: add-migration, update-database, code-first schema changes, seeding data, rollbacks, and production migration strategies.' date: 2026-06-28 lastmod: 2026-06-28 weight: 23 tags: [backend, aspnet]


EF Core migrations allow evolving the database schema as the application changes, tracking modifications in C# code and generating corresponding SQL for databases.

## What You'll Learn

By the end of this tutorial, you'll create and apply migrations, manage schema changes, seed initial data, roll back problematic migrations, and deploy migrations to production safely.

## Real-World Use

A CI/CD pipeline runs `dotnet ef database update` as a release step. Each deployment applies pending migrations automatically. Failed migrations trigger rollback and alerting.

## Migrations Learning Path

```mermaid
flowchart LR
  A[EF Core] --> B[Migrations]
  B --> C[Auth]
  C --> D[JWT]
  D --> E[Web API]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Setup Migrations Tools

# Install dotnet-ef tool globally
dotnet tool install --global dotnet-ef

# Verify installation
dotnet ef --version

# Install required NuGet packages
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

Creating Migrations

# Create initial migration
dotnet ef migrations add InitialCreate

# Add migration with description
dotnet ef migrations add AddProductTable

# Check what will be generated (script)
dotnet ef migrations script --idempotent
// Generated migration file
public partial class AddProductTable : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Products",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
                Price = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
                CategoryId = table.Column<int>(type: "int", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Products", x => x.Id);
                table.ForeignKey(
                    name: "FK_Products_Categories_CategoryId",
                    column: x => x.CategoryId,
                    principalTable: "Categories",
                    principalColumn: "Id",
                    onDelete: ReferentialAction.Cascade);
            });
        migrationBuilder.CreateIndex(
            name: "IX_Products_CategoryId",
            table: "Products",
            column: "CategoryId");
    }
    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(name: "Products");
    }
}

Applying Migrations

# Apply all pending migrations
dotnet ef database update

# Apply to a specific migration
dotnet ef database update AddProductTable

# Generate SQL script (safe for production)
dotnet ef migrations script -o migrate.sql

# Rollback to a previous migration
dotnet ef database update InitialCreate

Seeding Data

public class AppDbContext : DbContext
{
    public static void SeedData(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Category>().HasData(
            new Category { Id = 1, Name = "Electronics" },
            new Category { Id = 2, Name = "Clothing" }
        );
        modelBuilder.Entity<Product>().HasData(
            new Product { Id = 1, Name = "Laptop", Price = 999.99m, CategoryId = 1 },
            new Product { Id = 2, Name = "Phone", Price = 699.99m, CategoryId = 1 }
        );
    }
}
// Call in OnModelCreating
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    SeedData(modelBuilder);
}
// Generate migration for seed data
dotnet ef migrations add SeedCategoriesAndProducts

Production Migrations

// Program.cs - auto-migrate on startup (development only)
if (app.Environment.IsDevelopment())
{
    using var scope = app.Services.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    await db.Database.MigrateAsync();
}
# Production deployment script
# 1. Generate idempotent SQL script
dotnet ef migrations script --idempotent -o deploy.sql
# 2. Review and execute
sqlcmd -S production-server -d MyApp -i deploy.sql

Common Mistakes

1. Running Migrations Automatically in Production

Auto-migrate in development only. Production should use scripts reviewed by DBAs.

2. Deleting Migration Files

Never delete migration files that have been applied to any database. Create a new migration to undo changes.

3. Not Testing Down Migrations

Always verify that Down() correctly reverts changes. Rollbacks must work in emergencies.

4. Large Migration Files

Frequent small migrations are better than one massive migration. Each migration should be focused and reviewable.

5. Ignoring Seed Data Idempotency

Seed with HasData() (part of migration) rather than manual inserts. HasData checks if data exists.

Practice Questions

1. What is an EF Core migration?

A C# class that describes database schema changes. Up() applies changes, Down() reverts them.

2. How do you add a new column to an existing table?

dotnet ef migrations add AddDescriptionToProducts, then add the property to your entity class. EF detects the change.

3. How do you roll back a migration?

dotnet ef database update or apply the Down() method.

4. What is an idempotent migration script?

A SQL script that checks migration state before applying. Safe to run multiple times.

5. Challenge: Create a migration that adds a Rating column to the Product table.

# Add property to Product.cs
public double? Rating { get; set; }
# Create migration
dotnet ef migrations AddRatingToProducts
# Review generated code

FAQ

Can I rename a migration?

No. Migration names are embedded in the __EFMigrationsHistory table. Create a new migration instead.

What if two developers add migrations at the same time?

One developer rebases. The migration with a later timestamp applies second. Fix conflicts in the migration snapshot.

How do I revert seed data?

Remove the HasData() call and create a new migration. The new migration removes the seeded rows.

Can I use migrations with PostgreSQL?

Yes. Use Npgsql provider with the same dotnet ef commands.

What is the __EFMigrationsHistory table?

Tracks which migrations have been applied. EF Core checks this table to determine pending migrations.

Mini Project: Complete Migration Workflow

Create, apply, seed, and script migrations.

dotnet ef migrations add InitialCreate
dotnet ef database update
# Add seed data
dotnet ef migrations AddSeedData
dotnet ef migrations script -o deploy.sql

What's Next

ASP.NET Core Authentication ASP.NET Core JWT

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro