Skip to content

Repository files navigation

ef-migration-safety

NuGet NuGet Downloads License: MIT

Two packages ship from this repo:

  • EfMigrationSafety.Cli — a dotnet tool for running checks from the command line or CI.
  • EfMigrationSafety.Analyzers — the underlying analyzer library, for projects (e.g. custom tooling, MCP servers) that want to run the checks programmatically.

Static safety analyzer for EF Core migrations. Catch destructive operations before they hit your database.


Why this exists

EF Core migrations are powerful — and silent. A DropColumn followed by an AddColumn on the same column looks reasonable in a diff, compiles without warnings, and passes CI. Then it runs against production and destroys every value in that column. A non-nullable column added without a default value fails silently in development (empty table) and explodes on first deploy to a real database. By the time you realize what happened, the rollback window has closed.

ef-migration-safety runs as a CI step and flags these patterns statically, before the migration ever touches a database. It reads .cs migration files, parses them with Roslyn, and reports anything that has historically caused production incidents.


Install

CLI (command-line / CI usage)

dotnet tool install -g EfMigrationSafety.Cli

Library (programmatic usage)

dotnet add package EfMigrationSafety.Analyzers
using EfMigrationSafety.Analyzers;
using Microsoft.CodeAnalysis.CSharp;

var root = CSharpSyntaxTree.ParseText(migrationSource).GetRoot();

IMigrationAnalyzer[] analyzers =
[
    new DropAddColumnAnalyzer(),
    new NonNullableWithoutDefaultAnalyzer(),
    // ...the remaining analyzers
];

var issues = analyzers.SelectMany(a => a.Analyze(root, filePath));

Usage

# Analyze all migrations in a directory
ef-migration-safety check ./src/MyApp/Migrations

# Fail the build on any warnings (useful in CI)
ef-migration-safety check ./src/MyApp/Migrations --strict

# Output as JSON for downstream tooling
ef-migration-safety check ./src/MyApp/Migrations --output json

Example output

20240315120000_ChangeEmailColumnType.cs
  ⚠ Line 18: DropColumn + AddColumn pattern detected for column 'Email' (potential data loss). Use RenameColumn instead to preserve data.
    Recommendation: If this is a rename, replace with migrationBuilder.RenameColumn(). If this is intentional column replacement, document the data backfill strategy.

20240320100000_RenameEmailColumn.cs
  ℹ Line 12: Column rename detected: 'Email' → 'EmailAddress' on table 'Users'. Ensure all application code, queries, and ORM mappings referencing 'Email' are updated in the same deployment.
    Recommendation: Search the codebase for the old name before deploying. Common locations: entity classes, LINQ queries, raw SQL, stored procedures, reports, integration mappings.

Summary: 10 file(s) clean, 1 with info, 1 with warnings.

Checks

Analyzer Status What it catches
DropAddColumn Implemented DropColumn + AddColumn on the same column name inside Up() — destroys all column data
NonNullableWithoutDefault Implemented Adding a non-nullable column to an existing table without a default value — fails on non-empty tables
EmptyDownMethod Implemented Down() method that is empty or throws NotImplementedException — makes rollbacks impossible
RenameOperation Implemented (Info) RenameColumn / RenameTable without coordinated application code update — breaks running instances
AlterColumnTruncation Implemented AlterColumn reducing the size of nvarchar, varchar, char, or nchar columns — causes silent data truncation in production if existing rows exceed the new size
SqlInjection Implemented Raw migrationBuilder.Sql() called with an interpolated string, string concatenation, or string.Format — potential SQL injection via dynamic SQL construction
NoDataLoss Implemented AlterColumn reducing decimal precision or scale, or making a column non-nullable without a defaultValue — risks truncating or rejecting existing data
MissingIndexOnForeignKey Implemented AddColumn for a likely foreign key column with no matching CreateIndex — causes slow lookups and full table scans as the table grows
PotentiallyLossyTypeConversion Implemented AlterColumn narrowing an integer type (bigintint) or converting a string column to a non-string type — fails or truncates on existing data

Roadmap

See ROADMAP.md for the full list of planned checks. Near-term additions:

  • Detect index creation on large tables without ONLINE = ON
  • Detect missing transactions wrapping multi-step migrations
  • --baseline flag to suppress known-safe issues with an inline comment

Contributing

Contributions welcome. See CONTRIBUTING.md for setup instructions and the analyzer interface.


License

MIT — see LICENSE.

About

Static safety analyzer for EF Core migrations. Catches DropColumn + AddColumn data loss, missing defaults, empty Down() methods, and unsafe rename operations before they reach production.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages