Rules and best practices for .NET projects using Entity Framework Core. Claude uses this automatically when working with EF Core migrations, DbContext classes, entity models, or any dotnet ef commands.
You are working in a .NET project that uses Entity Framework Core. Follow these rules strictly.
When you start working in an EF Core project, orient yourself by detecting:
DbContext. Note which project and file they live in.Migrations/ directory containing *ModelSnapshot.cs. This is the model project.Program.cs (or Startup.cs) that configures the host and registers the DbContext with dependency injection.Program.cs are in different projects, all dotnet ef commands need --project and --startup-project flags.--context <ContextName>Expose this information to the user when running EF commands so they understand the project topology.
The following files are auto-generated by EF Core tooling and must never be edited by hand:
*.Designer.cs files in the Migrations directory — model snapshots at each migration point*ModelSnapshot.cs files — current model state used to compute the next migrationIf these files need to change, use dotnet ef migrations add or dotnet ef migrations remove to regenerate them. Hand-editing will corrupt migration history and cause unpredictable failures.
dotnet ef can pick up unrelated snapshot drift from NuGet package upgrades or other model changes. The generated Up() method should only contain the intended changes. Before committing a migration:
RenameColumn() insteadWhen adding a non-nullable column to an existing table, the migration must include a defaultValue or defaultValueSql. Otherwise the migration will fail on tables that already have rows.
// WRONG — will fail if the table has existing rows
migrationBuilder.AddColumn<string>(
name: "Status",
table: "Orders",
nullable: false);
// CORRECT — provides a default for existing rows
migrationBuilder.AddColumn<string>(
name: "Status",
table: "Orders",
nullable: false,
defaultValue: "Pending");
If dotnet ef migrations add generates a non-nullable column without a default, flag it and suggest a fix.
Microsoft.EntityFrameworkCore.Design must be installed as a permanent dependency on both the model project and the startup project. Do not add/remove it per migration. It is required for all dotnet ef commands to work.
Do not combine unrelated schema changes in a single migration. Each migration should correspond to one logical feature or change. This makes rollbacks cleaner and migration history readable.
The main migration file ([Timestamp]_MigrationName.cs) containing Up() and Down() methods can be edited when necessary. Common reasons:
migrationBuilder.RenameColumn() to preserve datamigrationBuilder.Sql() calls for data transformationsdefaultValue or defaultValueSql to non-nullable columnsmigrationBuilder.InsertData()Always keep Up() and Down() in sync — every change in Up() must be reversed in Down().
dotnet ef requires a valid connection string at build time, even for operations like migrations add that don't touch the database. If a command fails due to a missing connection string:
set "ConnectionStrings__DefaultConnection=Server=.;Database=EfCoreDummy;Integrated Security=false;User Id=dummy;Password=dummy;TrustServerCertificate=True"
(On Linux/macOS use export instead of set)dotnet ef migrations add DescriptiveNamedotnet ef database updateUse descriptive migration names that indicate purpose:
AddProductTable — adding a new tableAddCreatedAtToOrders — adding a columnRenameUserNameToFullName — renamingAddIndexOnEmail — adding an indexRemoveDeprecatedFields — cleanupAvoid generic names like Update, Changes, Fix.
dotnet ef migrations removePrefer generating SQL scripts or migration bundles over running dotnet ef database update directly:
dotnet ef migrations script --idempotent -o deploy.sqldotnet ef migrations bundle --self-containedcontext.Database.MigrateAsync() at startup in production — it causes race conditions and can't be easily rolled backAll dotnet ef commands support these options:
--project <PATH> (-p) — project containing the DbContext--startup-project <PATH> (-s) — project that configures the host and connection string--context <NAME> (-c) — DbContext class to use (required when multiple exist)--configuration <CONFIG> — build configuration (Debug/Release)--framework <TFM> — target framework (for multi-targeted projects)--verbose (-v) — show detailed output--no-build — skip building the project (use if already built)For the full command reference, see commands-reference.md.
IEntityTypeConfiguration<T> classes to organize configurations per entityOnModelCreating via modelBuilder.ApplyConfigurationsFromAssembly()Id or <EntityName>Id) and foreign keys (<NavigationProperty>Id).AsNoTracking() for read-only queries.Select()) to load only needed columnsIQueryable to compose queries before execution.Include() or projectionsWhere() or Select() that runs on IQueryable. Materialize with ToListAsync() first, then apply client-side logic in memory.dotnet ef dbcontext optimize) for improved startup performance in productionnvarchar(max) is the default if no MaxLength is specified. Always set explicit lengths for indexed string columns.ProjectName/
├── Data/
│ ├── ApplicationDbContext.cs
│ ├── Migrations/
│ │ ├── 20250101120000_InitialCreate.cs
│ │ ├── 20250101120000_InitialCreate.Designer.cs
│ │ └── ApplicationDbContextModelSnapshot.cs
│ └── Configuration/ (IEntityTypeConfiguration classes)
│ ├── BlogConfiguration.cs
│ └── PostConfiguration.cs
├── Models/ (or Entities/)
│ ├── Blog.cs
│ └── Post.cs
└── Program.cs
When the project uses a separate data layer:
--project and --startup-project flags with dotnet ef commandsWhen multiple DbContext classes exist, always specify which one:
dotnet ef migrations add MigrationName --context MyDbContext
dotnet ef database update --context MyDbContext