Database migration framework for .NET: raw SQL and C# code migrations, downgrades, long-running data migrations and per-environment policies for PostgreSQL and SQL Server.
Renamed: formerly
Curiosity.Migrations*by SIIS Ltd. Since 5.0.0 the packages are published asCuriosus.Migrations*by curiosus-dev. To migrate, replaceCuriositywithCuriosusin package references and code.-- CURIOSITY:directives in SQL scripts keep working.
Curiosus.Migrations is a database migration framework for .NET (net9.0 and net10.0; stay on 5.x for older runtimes) that gives you precise control over how your database evolves. It keeps raw SQL scripts and C# code migrations in one ordered history, so a schema change and the data migration that goes with it are versioned, applied and rolled back together.
Unlike ORM-specific migration tools, Curiosus.Migrations is database-focused and designed for scenarios where you need fine-grained control over migration execution, especially for large production databases where heavy data migrations must not block a deployment.
|
Write raw SQL when you need optimal performance, or use C# code when you need complex logic. You control exactly what runs against your database. |
Long-running migration support and policies that decide what runs in each environment: quick schema changes on deployment, heavy data migrations separately. |
|
Downgrade scripts and code migrations roll the database back to a target version when a deployment doesn't go as planned. |
Separate long-running data migrations from quick schema changes to keep your application responsive during upgrades. |
|
Create and initialize test databases with specific migration states for reliable integration testing. |
Customize where migrations come from, how they're logged, and how they're applied to fit your workflow. |
-
Script Migrations: Write raw SQL for direct database access
- Batched Execution: Split large scripts into manageable chunks
- Full support for database-specific SQL features and optimizations
-
Code Migrations: Implement migrations in C# for complex scenarios
- Dependency Injection: Use your application's services in migrations
- Entity Framework Integration: Leverage EF Core when needed
- Any C# logic: data transformations, calls to your services, batched updates
- Policies: Control which migrations run in different environments
- Dependencies: Specify explicit requirements between migrations
- Downgrade Migrations: Safely roll back changes when needed
- Transactions: Configure transaction behavior per migration
- Long-running vs Short-running: Separate quick schema changes from data-intensive operations
- Migration Providers: Source migrations from files, embedded resources, etc.
- Variables: Dynamic value substitution in migrations
- Pre-migrations: Run setup scripts before main migrations
- Custom Journal: Configure how applied migrations are tracked
# Install core package
dotnet add package Curiosus.Migrations
# Install database provider (PostgreSQL or SQL Server)
dotnet add package Curiosus.Migrations.PostgreSQL
# or
dotnet add package Curiosus.Migrations.SqlServerPut SQL scripts named by version into a directory: 1.0-create_users.sql, 1.1.up.sql with its 1.1.down.sql, and so on. Then configure and run the engine:
using System.Reflection;
using Curiosus.Migrations;
using Curiosus.Migrations.PostgreSQL;
var builder = new MigrationEngineBuilder();
// UseScriptMigrations() and UseCodeMigrations() return the providers, not the builder: configure them separately
builder.UseScriptMigrations().FromDirectory("./Migrations");
builder.UseCodeMigrations().FromAssembly(Assembly.GetExecutingAssembly());
builder.ConfigureForPostgreSql("Host=localhost;Database=myapp;Username=postgres;Password=secret");
builder.UseUpgradeMigrationPolicy(MigrationPolicy.AllAllowed);
var migrationEngine = builder.Build();
var result = await migrationEngine.UpgradeDatabaseAsync();
if (!result.IsSuccessfully)
{
throw new InvalidOperationException(
$"Migration {result.FailedMigration?.Version} failed: {result.ErrorCode} {result.ErrorMessage}",
result.Exception);
}
Console.WriteLine($"Applied {result.AppliedMigrations.Count} migrations");The engine creates the database and the migration history table when they are missing. A complete runnable example with script, code and downgrade migrations is in samples/Curiosus.Migrations.Sample.
Get started quickly with the Quick Start Guide or dive into Core Concepts.
No concurrency lock yet. The engine doesn't lock the database while it migrates, so two instances starting at the same time can apply the same migration twice or fail on the journal. Until #32 lands, run migrations from one place: a Kubernetes Job or init container, a deployment pipeline step, or the startup of a single replica.
PostgreSQL |
SQL Server |
MySQL/MariaDB (#37) and SQLite (#38) are planned for v7, after the engine rework that makes a new database a small dialect (#36). A custom IMigrationConnection can add any other database.
As of October 2026. ✅ supported,
| Curiosus.Migrations | EF Core Migrations | FluentMigrator | DbUp | grate | Flyway | Liquibase | |
|---|---|---|---|---|---|---|---|
| Migrations written as | SQL + C# code | C# generated from the EF model (+ raw SQL) | Fluent C# API (+ raw SQL) | SQL (+ IScript code) |
SQL | SQL (+ Java) | XML/YAML/JSON/SQL changelogs |
| Databases | PostgreSQL, SQL Server | Any EF Core relational provider | 6 | 7 | 5 | 20+ | 50+ |
| Downgrade / rollback | ✅ Hand-written, free | ✅ Generated Down() |
✅ Down(), auto-reversing |
❌ | ❌ | 💰 Undo | ✅ (targeted rollback 💰) |
| Long-running vs short-running policies | ✅ | ❌ | |||||
| Dependencies between migrations | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | |
| C# migrations with DI | ✅ | ✅ | IScript |
❌ | ❌ | ❌ | |
| Concurrency lock | ❌ #32 | ✅ Since EF Core 9 | ❌ | ❌ | Not documented | ✅ | ✅ |
| Checksums, drift detection | ❌ #33 | ❌ | ❌ | ✅ | ✅ (drift report 💰) | ✅ (drift 💰) | |
| Repeatable migrations | ❌ #39 | ❌ | ✅ | ✅ | ✅ | ✅ | |
| CLI, dry-run, SQL preview | ❌ #40, #42 | ✅ dotnet ef, bundles, scripts |
✅ dotnet-fm |
✅ | ✅ | ✅ | |
| License | MIT | MIT | Apache-2.0 | MIT | MIT | Apache-2.0 core, paid editions | FSL core, paid editions |
The gaps are planned for v7, see the roadmap. Evolve had checksums and locking but has had no stable release since 3.2.0 (June 2023); RoundhousE is superseded by grate.
Choose Curiosus.Migrations when you mix hand-tuned SQL with C# data migrations on PostgreSQL or SQL Server, need heavy backfills kept out of the deployment path, and want free downgrades. Choose something else when your app is EF Core-centric with one schema owner (EF Core Migrations), you target many database engines or want a fluent schema DSL (FluentMigrator), you only need forward-only SQL scripts (DbUp, or grate with hash checks and a CLI), or a DBA-led team needs compliance and drift reports (Flyway, Liquibase).
For a detailed comparison, see The Philosophy Behind Curiosus.Migrations.
| Package | Version | Downloads | Coverage |
|---|---|---|---|
| Curiosus.Migrations | |||
| Curiosus.Migrations.PostgreSQL | |||
| Curiosus.Migrations.SqlServer | |||
| Curiosus.Migrations.Utils |
- GitHub Issues - Report bugs or request features
Curiosus.Migrations is licensed under the MIT License.
