StewardEF 0.4.0
See the version list below for details.
dotnet tool install --global StewardEF --version 0.4.0
dotnet new tool-manifest
dotnet tool install --local StewardEF --version 0.4.0
#tool dotnet:?package=StewardEF&version=0.4.0
nuke :add-package StewardEF --version 0.4.0
StewardEF 🛠️
StewardEF is a tool designed to make managing Entity Framework (EF) migrations easier for projects with a lengthy history. Specifically, it is able to squash your migrations back to a single file and drastically speed up your build times.
EF Core does not yet provide a built-in solution for squashing migrations yet (relevant issue here), but in the meantime, StewardEF can help fill the gap.
Installation
Install the StewardEF dotnet tool:
dotnet tool install -g StewardEF
Commands
squash
Squashes EF migrations into the first migration in the specified directory.
Usage:
steward squash path/to/migrations [-y year] [-t migration-name]
Options
[MigrationsDirectory]: Path to the directory containing your EF migrations. If omitted, you'll be prompted to enter it interactively.-y|--year: Optional. Specify the year up to which migrations should be squashed. If omitted, all migrations will be squashed.-t|--target: Optional. Specify the target migration name (without .cs extension) up to which migrations should be squashed. Since EF Core migrations follow the patternYYYYMMDDHHMMSS_MigrationName.cs, you can specify either the full name (e.g. "20230615000000_AddUserTable") or just part of it (e.g. "AddUserTable"). The matching is case-insensitive. If omitted, all migrations will be squashed.--skip-sql: Optional. Skip automatic SQL conversion even if problematic rename operations are detected. A warning will be shown if rename-then-drop patterns are found. Use this if you want to keep the C# code format and handle any issues manually.
Examples
# Squash all migrations
steward squash path/to/migrations
# Squash migrations from 2023
steward squash path/to/migrations -y 2023
# Squash migrations up to a specific migration (using full name)
steward squash path/to/migrations -t 20230615000000_AddUserTable
# Squash migrations up to a specific migration (using partial name)
steward squash path/to/migrations -t AddUserTable
# Squash migrations but skip SQL conversion (keep C# format)
steward squash path/to/migrations --skip-sql
How It Works
⚠️ The squash command will modify your migrations files, so please be sure to start with a clean commit before squashing so you can easily undo your changes if needed
The squash command combines all existing migrations into a single, consolidated migration file. Here's how it works:
- C# Aggregation: Combines the Up and Down methods across all migration files using standard C# code concatenation
- Using Statements: Collects using statements from all migrations, ensuring no dependencies are missed
- Designer File Update: Renames the latest designer file to match the first migration and updates its metadata
- Cleanup: Deletes all intermediate migrations, leaving only the squashed first migration
- Automatic Rename Detection (post-squash): Scans the squashed result for problematic rename-then-drop patterns (e.g.,
RenameColumnfollowed byDropColumnof the renamed column) - SQL Conversion (if needed): If a renamed entity is subsequently dropped, automatically converts the squashed migration to SQL format
Why? When EF executes rename operations, it needs the designer file to validate that the column/table exists. If a column is renamed then later dropped, the final designer snapshot won't contain it, causing "could not be found in target model" errors. Converting to SQL captures the correct schema transformations without relying on designer metadata.
Note: Simple renames without a subsequent drop are safe and won't trigger SQL conversion.
Handling Rename Operations
The tool detects rename-then-drop patterns - cases where a column, table, or index is renamed and then subsequently dropped. These patterns are problematic because the drop operation references an entity by its new name, but the final model snapshot doesn't know about the rename history.
When problematic patterns are detected, you'll see output like this:
Squashing 15 migration files...
Migrations squashed successfully! ✨
⚠ Detected rename operations in squashed migration
Converting to SQL script format...
Found project: MyApp.csproj
✓ Successfully converted to SQL format
The tool automatically:
- Squashes migrations normally using C# code concatenation
- Checks for rename-then-drop patterns (e.g.,
RenameColumn→DropColumnfor the same column) - If found, locates your
.csprojfile (searches up the directory tree) - Generates SQL scripts using
dotnet ef migrations script 0 <migration-id> - Replaces the squashed migration content with
migrationBuilder.Sql()calls containing the generated SQL
Skipping SQL Conversion
If you prefer to keep the C# format and handle any issues manually, use the --skip-sql flag:
steward squash path/to/migrations --skip-sql
When skipped, you'll see a warning if problematic patterns are detected:
⚠ Warning: Detected rename operations (RenameColumn, RenameTable, or RenameIndex) in squashed migration
SQL conversion was skipped due to --skip-sql flag
The squashed migration may have issues when applied to a fresh database
This approach solves the common issue where squashed migrations fail with errors like "The column 'X' could not be found in target model" when columns are renamed then later dropped. By converting to SQL after squashing, the tool preserves the correct schema transformations without depending on intermediate designer files.
Things to Watch For
Depending on how your migrations were structured, you might need to make some manual adjustments after running squash:
- Private Fields: If any private readonly fields or other member data are in your migrations, ensure they're properly defined in the combined migration file
- Custom C# Logic: Complex data transformations or C# code beyond schema changes may not convert perfectly to SQL
- Testing: Always test squashed migrations on a clean database to verify they work correctly
convert-to-sql
Converts an existing migration to use SQL scripts instead of C# code. This is useful when you need to manually convert a migration that has rename operations or other issues that would benefit from SQL representation.
Usage:
steward convert-to-sql path/to/migrations [-p project-path] [-m migration-name]
Options
[MigrationsDirectory]: Path to the directory containing your EF migrations. If omitted, you'll be prompted to enter it interactively.-p|--project: Optional. Explicit path to your.csprojfile. If omitted, the tool will search up the directory tree.-m|--migration: Optional. Name of the specific migration to convert (without .cs extension). If omitted, converts the most recent migration.
Examples
# Convert the most recent migration
steward convert-to-sql path/to/migrations
# Convert with explicit project path
steward convert-to-sql path/to/migrations -p path/to/MyProject.csproj
# Convert a specific migration
steward convert-to-sql path/to/migrations -m AddUserTable
steward convert-to-sql path/to/migrations -m 20231201000000_AddUserTable
How It Works
The convert-to-sql command:
- Locates the specified migration (or most recent if not specified)
- Finds the associated
.Designer.csfile to extract the migration ID - Uses
dotnet ef migrations scriptto generate SQL for the Up and Down methods - Replaces the migration's C# code with
migrationBuilder.Sql()calls containing the generated SQL
This is particularly useful for:
- Fixing problematic migrations after they've been created
- Converting migrations that will be deployed to production via SQL scripts
- Working around EF limitations with rename operations in complex scenarios
Note: This command requires the
dotnet eftools to be installed and your project to be buildable.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.5.0-preview.3 | 229 | 12/18/2025 |
| 0.5.0-preview.2 | 221 | 12/17/2025 |
| 0.5.0-preview.1 | 226 | 12/17/2025 |
| 0.4.0 | 280 | 12/17/2025 |
| 0.3.0 | 295 | 11/12/2025 |
| 0.2.0 | 226 | 11/10/2025 |
| 0.1.3 | 307 | 11/12/2024 |
| 0.1.2 | 160 | 11/12/2024 |
| 0.1.1 | 167 | 11/11/2024 |
| 0.1.0 | 167 | 11/11/2024 |