Friday, September 11, 2026

EF Core 11.0: What's New with Migrations

.NET 11 Release Candidate 1 is out, and that means we are getting really close to the finish line. Next month we should get RC2, and then in November the GA release at .NET Conf 2026. You can read more about RC1 here: Announcing .NET 11 Release Candidate 1.

In this post, let's have a look at some of the nice improvements that are coming to EF Core 11.0 Migrations. There are quite a few of them, but I am going to focus on the following three.
  • Excluding foreign key constraints from migrations
  • Create and apply migrations in one step
  • Connection and offline options for migrations remove
First, the project file. I am using the latest RC as of today, it will change.
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net11.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="11.0.0-rc.1.26425.128">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="11.0.0-rc.1.26425.128" />
  </ItemGroup>

</Project>

And make sure you have the matching version of the dotnet-ef tool.
dotnet tool update -g dotnet-ef --version 11.0.0-rc.1.26425.128

Excluding foreign key constraints from migrations


Say you are working with a legacy database that doesn't have foreign key constraints, or you have some data synchronization process where referential integrity constraints get in the way of the synchronization order. You still want EF Core to know about the relationship, but you don't want migrations to create the constraint in the database.

With EF Core 11.0, we now have ExcludeForeignKeyFromMigrations() for exactly that. Consider the following entities.
public class Customer
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class Order
{
    public int Id { get; set; }

    public string OrderNumber { get; set; }

    public Customer Customer { get; set; }

    public int CustomerId { get; set; }
}
And here is the DbContext. The relationship is configured as usual, and we just call ExcludeForeignKeyFromMigrations() at the end.
public class MyDbContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }

    public DbSet<Order> Orders { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseSqlServer(@"<ConnectionString>")
            .LogTo(Console.WriteLine, LogLevel.Information);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .HasOne(x => x.Customer)
            .WithMany()
            .HasForeignKey(x => x.CustomerId)
            .ExcludeForeignKeyFromMigrations();
    }
}
When we add a migration, the Orders table no longer has a ForeignKey constraint. Note that an index is still created on the foreign key column.
protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "Customers",
        columns: table => new
        {
            Id = table.Column<int>(type: "int", nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            Name = table.Column<string>(type: "nvarchar(max)", nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Customers", x => x.Id);
        });

    migrationBuilder.CreateTable(
        name: "Orders",
        columns: table => new
        {
            Id = table.Column<int>(type: "int", nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            OrderNumber = table.Column<string>(type: "nvarchar(max)", nullable: false),
            CustomerId = table.Column<int>(type: "int", nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Orders", x => x.Id);
        });

    migrationBuilder.CreateIndex(
        name: "IX_Orders_CustomerId",
        table: "Orders",
        column: "CustomerId");
}
The relationship itself is fully supported in EF Core for queries, change tracking etc. Only the constraint in the database is suppressed.
using var context = new MyDbContext();

Customer customer = new() 
{
Name = "John Doe"
}; await context.Customers.AddAsync(customer); await context.Orders.AddRangeAsync( new Order { OrderNumber = "ORD-001", Customer = customer }, new Order { OrderNumber = "ORD-002", Customer = customer }); await context.SaveChangesAsync(); foreach (Order order in await context.Orders .Include(x => x.Customer) .ToListAsync()) { Console.WriteLine($"Order: '{order.OrderNumber}', Customer: '{order.Customer.Name}'."); } // Query //SELECT[o].[Id], [o].[CustomerId], [o].[OrderNumber], [c].[Id], [c].[Name] //FROM[Orders] AS[o] //INNER JOIN[Customers] AS [c] ON[o].[CustomerId] = [c].[Id] // Output // Order: 'ORD-001', Customer: 'John Doe'. // Order: 'ORD-002', Customer: 'John Doe'

Create and apply migrations in one step


Up until now, create and apply migrations has always been two commands: dotnet ef migrations add followed by dotnet ef database update. With EF Core 11.0, dotnet ef database update has a new --add option that scaffolds the migration, compiles it at runtime using Roslyn, and applies it to the database, all in one go.
dotnet ef database update InitialCreate --add
And the output (trimmed):
Build started...
Build succeeded.
Creating and applying migration 'InitialCreate'.
...
Applying migration '20260911004844_InitialCreate'.
...
      CREATE TABLE [Customers] (
          [Id] int NOT NULL IDENTITY,
          [Name] nvarchar(max) NOT NULL,
          CONSTRAINT [PK_Customers] PRIMARY KEY ([Id])
      );
...
      CREATE TABLE [Orders] (
          [Id] int NOT NULL IDENTITY,
          [OrderNumber] nvarchar(max) NOT NULL,
          [CustomerId] int NOT NULL,
          CONSTRAINT [PK_Orders] PRIMARY KEY ([Id])
      );
...
      CREATE INDEX [IX_Orders_CustomerId] ON [Orders] ([CustomerId]);
...
Migration '20260911004844_InitialCreate' was successfully created and applied.
The migration files are still written to disk, so you can commit them to source control as usual. All the options you would use with dotnet ef migrations add are supported as well.

If you are using the Package Manager Console, you can use the -Add parameter.
Update-Database -Migration InitialCreate -Add

Connection and offline options for migrations remove


dotnet ef migrations remove and dotnet ef database drop now accept a --connection option, so we can pass in the connection string directly instead of relying on whatever is configured in the DbContext.
# Remove migration using a specific connection
dotnet ef migrations remove --connection "<Connection String>"

# Drop a specific database using a connection string
dotnet ef database drop --connection "<Connection String>" --force
And migrations remove has a new --offline option. Previously, migrations remove always connected to the database to check whether the migration had been applied. With --offline, that check is skipped entirely, which is useful when the database isn't reachable or when you know the migration hasn't been applied.
dotnet ef migrations add InitialCreate
dotnet ef migrations remove --offline
And the output:
Build started...
Build succeeded.
Removing migration '20260911004851_AddOrderDate'.
Reverting the model snapshot.
Done.
Note that --offline and --force can't be used together. --force reverts the migration if it has been applied, and to know that, it needs a database connection.
# The --offline and --force options cannot be used together.
dotnet ef migrations remove --offline --force
In the Package Manager Console, use the -Connection and -Offline parameters.
Remove-Migration -Connection "<Connection String>"
Remove-Migration -Offline
Drop-Database -Connection "<Connection String>" -Force
There are more migration improvements in EF Core 11.0 like the latest migration ID being recorded in the model snapshot, a configuration file for dotnet ef, -NoBuild for PMC commands, and wildcard context support. Do check them out.

More read:

Hope this helps.

Happy Coding.

Regards,
Jaliya