Chd.Library.Migrations
8.6.4
dotnet add package Chd.Library.Migrations --version 8.6.4
NuGet\Install-Package Chd.Library.Migrations -Version 8.6.4
<PackageReference Include="Chd.Library.Migrations" Version="8.6.4" />
<PackageVersion Include="Chd.Library.Migrations" Version="8.6.4" />
<PackageReference Include="Chd.Library.Migrations" />
paket add Chd.Library.Migrations --version 8.6.4
#r "nuget: Chd.Library.Migrations, 8.6.4"
#:package Chd.Library.Migrations@8.6.4
#addin nuget:?package=Chd.Library.Migrations&version=8.6.4
#tool nuget:?package=Chd.Library.Migrations&version=8.6.4
Migration Library for .NET Core
📝 Table of Contents
- About
- Features
- Quick Start
- How Migrations Are Applied
- Database Integration (DI)
- Configuration
- Writing Migrations
- Advanced Usage & Best Practices
- Production Tips & Troubleshooting
- FAQ
- Feature Comparison
- Authors
- Acknowledgements
About
Chd.Library.Migration is a production-ready, attribute-based, fluent database migration library for .NET Core.
Manage schema and data versioning for PostgreSQL, Oracle, MsSQL, and SQLite using clean C# and a proven migration approach.
No more SQL scripts or CLI headaches—get full control, auditability, and speed in all environments.
Features
- Attribute-based versioned migrations:
[Migration(version, author)] - Powerful fluent DSL for all schema/data operations: Create, Alter, Drop, Insert, Update, Delete, Index, Constraints, Execute SQL, and more.
- Auto-discovers all migration classes in your project (no manual registration)
- Runs all pending migrations automatically at app startup, in a background thread for speed and safety
- Tracks migration history using a dedicated
VersionInfotable - Supports both startup and on-demand migration triggers
- Fully thread-safe, standardized and production tested
- .NET 9.0+ support
Quick Start
Install:
dotnet add package Chd.Library.MigrationConfigure your connection strings:
"ConnectionStrings": { "PostgreSQLTest": "Host=localhost;Port=5432;Database=my_db;User ID=postgres;Password=xxx;", "OracleTest":"Data Source=...;User Id=...;Password=...;", "MsSQLTest": "Server=...;Database=...;User Id=...;Password=...;", "SQLiteTest": "Data Source=mydb.db;" }Register your migration(s) in DI (choose the database you use):
// In Program.cs builder.Services.AddMigration<Program>(DatabaseType.PostgreSQL, "PostgreSQLTest");
🚦 How Migrations Are Applied
- Automatic & Threaded:
On application startup, all pending migrations are executed in a background thread—keeping startup blazing-fast and never blocking the API/UI. - On-demand, anywhere:
Trigger migrations anytime withDatabaseMigration.RunMigration<T>(...)(CLI tools, admin panels, deployment hooks, etc.). - Single Source of Truth:
TheVersionInfotable records migration versioning and prevents accidental or duplicate runs—ensuring safety across all environments. - Production-Proven:
Battle-tested in multiple enterprise, microservice, and critical app deployments.
Database Integration (DI)
PostgreSQL
builder.Services.AddMigration<Program>(DatabaseType.PostgreSQL, "PostgreSQLTest");
Oracle
builder.Services.AddMigration<Program>(DatabaseType.Oracle, "OracleTest");
MsSQL
builder.Services.AddMigration<Program>(DatabaseType.MsSQL, "MsSQLTest");
SQLite
builder.Services.AddMigration<Program>(DatabaseType.SQLite, "SQLiteTest");
On-demand Migration
DatabaseMigration.RunMigration<Program>(DatabaseType.PostgreSQL, "YourFullConnectionStringHere");
(Runs migrations on demand, in a background thread.)
Configuration
Set your databases in appsettings.json (or any .NET config provider):
"ConnectionStrings": {
"PostgreSQLTest": "Host=localhost;Port=5432;Database=my_db;User ID=postgres;Password=xxx;",
"OracleTest": "Data Source=...;User Id=...;Password=...;",
"MsSQLTest": "Server=...;Database=...;User Id=...;Password=...;",
"SQLiteTest": "Data Source=mydb.db;"
}
Writing Migrations
Schema Migration Example
[Migration(1, "Mehmet Yoldaş")]
public class StudentTableMigration : Migration
{
public override void Up()
{
Create.Table("student")
.WithIdColumn()
.WithColumn("first_name").AsString().NotNullable()
.WithColumn("last_name").AsString(255)
.WithColumn("user_name").AsString()
.WithColumn("birth_date").AsDate().Nullable();
}
public override void Down()
{
Delete.Table("student");
}
}
Creates a table with primary key and string/date columns. Down() removes it.
Data Migration Example
[Migration(1000001, "Mehmet Yoldaş")]
public class SeedStudents : Migration
{
public override void Up()
{
Insert.Into("student").Row(new { first_name = "Mehmet", last_name = "Yoldaş", user_name = "mehmetyoldas", birth_date = DateTime.Now });
Insert.Into("student").Row(new { first_name = "Ali", last_name = "Yılmaz", user_name = "aliyilmaz", birth_date = DateTime.Now });
}
public override void Down()
{
// Remove seeded data if possible
}
}
Inserts several rows; Down() can delete or ignore as needed.
Comprehensive Fluent Migration Reference
Below is a reference of the most common migration operations—with short explanations.
CREATE TABLE
Create.Table("users")
.WithIdColumn()
.WithColumn("name").AsString().NotNullable()
.WithColumn("email").AsString(255).Unique()
.WithColumn("created_at").AsDateTime().WithDefault(DateTime.UtcNow);
Create a table, use different column types, unique constraint, and default value.
ALTER TABLE (ADD COLUMN)
Alter.Table("users").AddColumn("is_active").AsBoolean().WithDefault(true);
Add a boolean column with default.
INSERT DATA
Insert.Into("users").Row(new { name = "Jane", email = "jane@site.com", created_at = DateTime.UtcNow });
Insert a row into a table.
UPDATE DATA
Update.Table("users").Set(new { email = "jane@newmail.com" }).Where(new { name = "Jane" });
Update matching rows using an anonymous object as WHERE filter.
DELETE DATA
Delete.From("users").Row(new { name = "Jane" });
Delete a row with matching field(s).
DROP COLUMN
Delete.Column("is_active").FromTable("users");
Remove a column.
CREATE INDEX
Create.Index("ix_users_email")
.OnTable("users")
.OnColumn("email")
.Ascending()
.Unique();
Index definition—ascending, unique.
ADD FOREIGN KEY
Create.ForeignKey("fk_orders_user")
.FromTable("orders").ForeignColumn("user_id")
.ToTable("users").PrimaryColumn("id")
.OnDelete(System.Data.Rule.Cascade);
Create a foreign key with cascade.
EXECUTE RAW SQL
Execute.Sql("UPDATE users SET is_active = 1 WHERE is_active IS NULL");
Direct SQL execution for advanced or data-fix scenarios.
RENAME TABLE / COLUMN
Rename.Table("old_users").To("users");
Rename.Column("surname").OnTable("users").To("last_name");
Rename any table or column.
Advanced Usage & Best Practices
- Don’t forget Down() methods: Guarantee safe rollbacks in migrations, especially for destructive ops.
- Versioning Strategy: Use ascending integer versions; recommend < 1,000,000 for schema, ≥ 1,000,000 for data.
- Chained/Multi-table migrations: You can create highly complex migration sequences, chained Up()/Down()’s for transactional/atomic deployment strategies.
- CI/CD Ready: Migrations are designed for hands-off automation—works perfectly in scalable, cloud-native environments.
Production Tips & Troubleshooting
- Migration not running?
- Confirm [Migration] attribute & base class; check namespace is discoverable.
- Ensure you call the correct
AddMigration<T>root class in DI.
- Migration errors:
- Fix the migration, re-deploy—system will retry safely. Check the
VersionInfotable for current state.
- Fix the migration, re-deploy—system will retry safely. Check the
- Order and atomicity:
- Always version and order migrations strictly! Never modify applied migrations—append new ones only for any fix.
- Failure Recovery:
- Well-written Down() enables you to revert migrations if you ever need emergency rollback.
FAQ
Q: Can I use the same library for multiple databases?
Yes, register each DB via AddMigration<T>(DatabaseType, ConnectionStringKey) in DI. Each keeps its own migration chain.
Q: I want to trigger migrations from an admin panel or after deployment.
Just use the On-Demand API:
DatabaseMigration.RunMigration<Program>(DatabaseType.MsSQL, "connectionstring");
Q: Is it safe for production, CI/CD, and cloud?
Absolutely! This system is running in high-availability production SaaS, web, and microservice environments.
Q: Can I write fully custom SQL if needed?
Yes—use the Execute.Sql(...) method for any edge-case, batch, or one-off data fix.
Feature Comparison
| Feature | Chd.Library.Migration | FluentMigrator | EF Core Migrations | Flyway (Java) |
|---|---|---|---|---|
| Attribute Versioning | ✅ | ✅ | ❌ | ❌ |
| Fluent C# DSL | ✅ | ✅ | Limited | ❌ |
| Multi-Database | ✅ | ✅ | Partial | ✅ |
| On-Demand Trigger | ✅ | ✅ | Partial | ✅ |
| DI Integration | ✅ | Partial | ✅ | ❌ |
| Battle-Tested | ✅ | ✅ | ✅ | ✅ |
Authors
- Mehmet Yoldaş (mehmet-yoldas)
See also contributors on NuGet
Acknowledgements
- Inspired by FluentMigrator, EF, and Flyway
- Special thanks to organizations and engineers who have tested and improved this library in critical production environments
For issues, feature requests or pull requests, visit mehmet-yoldas/library-core
| 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 was computed. 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 was computed. 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. |
-
net8.0
- Chd.Library.Core (>= 8.5.8)
- Chd.Library.Logging (>= 8.6.5)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.2.0)
- Microsoft.Data.Sqlite (>= 8.0.1)
- Microsoft.EntityFrameworkCore.Design (>= 8.0.1)
- Microsoft.EntityFrameworkCore.Sqlite (>= 8.0.1)
- Microsoft.EntityFrameworkCore.Sqlite.Core (>= 8.0.1)
- Microsoft.EntityFrameworkCore.SqlServer (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 8.6.4 | 94 | 1/20/2026 |
| 8.6.3 | 87 | 1/17/2026 |
| 8.6.2 | 91 | 1/15/2026 |
| 8.6.1 | 92 | 1/12/2026 |
| 8.6.0 | 95 | 1/12/2026 |
| 8.5.9 | 279 | 12/23/2025 |
| 8.5.8 | 151 | 12/20/2025 |
| 8.5.7 | 248 | 12/19/2025 |
| 8.5.6 | 244 | 12/19/2025 |
| 8.5.4 | 250 | 8/17/2025 |
| 8.5.3 | 447 | 8/3/2025 |
| 8.5.2 | 184 | 7/31/2025 |
| 8.5.1 | 601 | 7/23/2025 |
| 8.0.9 | 201 | 12/23/2024 |
| 8.0.8 | 188 | 12/23/2024 |
| 8.0.3 | 497 | 2/3/2024 |
| 8.0.2 | 456 | 2/3/2024 |
| 8.0.1 | 486 | 2/3/2024 |
| 8.0.0 | 473 | 1/30/2024 |
| 7.4.5 | 625 | 9/4/2023 |
| 7.4.4 | 581 | 9/4/2023 |
| 7.4.3 | 619 | 9/4/2023 |
| 7.4.2 | 692 | 9/4/2023 |
| 7.4.1 | 689 | 8/25/2023 |
| 7.4.0 | 678 | 8/18/2023 |
| 7.3.3 | 852 | 8/9/2023 |
| 1.3.3 | 842 | 5/28/2023 |
| 1.3.2 | 763 | 5/11/2023 |
| 1.3.1 | 817 | 4/28/2023 |
| 1.3.0 | 852 | 4/28/2023 |
| 1.2.9 | 898 | 4/24/2023 |
| 1.2.8 | 787 | 4/20/2023 |
| 1.2.7 | 1,084 | 1/30/2023 |
| 1.1.9 | 2,821 | 1/30/2023 |