AdaskoTheBeAsT.MongoDbMigrations
3.0.0
dotnet add package AdaskoTheBeAsT.MongoDbMigrations --version 3.0.0
NuGet\Install-Package AdaskoTheBeAsT.MongoDbMigrations -Version 3.0.0
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations" Version="3.0.0" />
<PackageVersion Include="AdaskoTheBeAsT.MongoDbMigrations" Version="3.0.0" />
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations" />
paket add AdaskoTheBeAsT.MongoDbMigrations --version 3.0.0
#r "nuget: AdaskoTheBeAsT.MongoDbMigrations, 3.0.0"
#:package AdaskoTheBeAsT.MongoDbMigrations@3.0.0
#addin nuget:?package=AdaskoTheBeAsT.MongoDbMigrations&version=3.0.0
#tool nuget:?package=AdaskoTheBeAsT.MongoDbMigrations&version=3.0.0
AdaskoTheBeAsT.MongoDbMigrations
A MongoDB migration library using the official MongoDB C# Driver to migrate your documents in database. This library supports on-premises MongoDB instances, Azure CosmosDB (MongoDB API), and AWS DocumentDB.
No more downtime for schema-migrations. Just write small and simple migrations.
Package Structure (v3.x)
The library is split into three NuGet packages for optimal deployment:
| Package | Purpose | When to Reference |
|---|---|---|
AdaskoTheBeAsT.MongoDbMigrations.Abstractions |
IMigration, Version, MigrationContext |
Migration class projects |
AdaskoTheBeAsT.MongoDbMigrations.SourceGenerators |
Compile-time migration registry generator | Migration class projects |
AdaskoTheBeAsT.MongoDbMigrations |
MigrationEngine, runtime execution |
Application startup/runner |
Typical Setup
In your migrations project (class library with migration classes):
<ItemGroup>
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations.Abstractions" Version="3.0.0" />
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations.SourceGenerators" Version="3.0.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
In your application (where migrations are executed):
<ItemGroup>
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations" Version="3.0.0" />
<ProjectReference Include="..\YourMigrations\YourMigrations.csproj" />
</ItemGroup>
Source Generator Architecture
This library uses compile-time source generators instead of runtime Roslyn analysis, providing significant advantages:
Why Source Generators?
| Aspect | Original Approach (Runtime Roslyn) | Source Generator Approach |
|---|---|---|
| Package Size | ~8MB (Microsoft.CodeAnalysis) | Minimal overhead |
| Startup Time | Slow (parses project at runtime) | Fast (pre-computed at compile) |
| AOT Compatible | No (heavy reflection) | Yes |
| Error Detection | Runtime failures | Compile-time errors |
| Collection Names | Parsed from source at runtime | Pre-extracted during build |
How It Works
At Compile Time: The source generator scans your migration classes, extracts version info, names, and MongoDB collection names used in
UpAsync/DownAsyncmethods.Generated Registry: A
MigrationRegistryclass is automatically generated containing all migration metadata:
// Auto-generated at compile time in AdaskoTheBeAsT.MongoDbMigrations.Generated namespace
[GeneratedMigrationRegistry]
public static class MigrationRegistry
{
public static IReadOnlyList<MigrationDescriptor> GetAllMigrations() => ...
}
- At Runtime: The
MigrationManagerautomatically discovers and uses the generated registry, resulting in faster startup and smaller deployment size.
What Gets Generated
For each migration class like:
public class AddUserIndex : IMigration
{
public Version Version => new Version(1, 0, 0);
public string Name => "Add index to users";
public async Task UpAsync(MigrationContext context)
{
var users = context.Database.GetCollection<BsonDocument>("users");
await users.Indexes.CreateOneAsync(...);
}
public async Task DownAsync(MigrationContext context)
{
var users = context.Database.GetCollection<BsonDocument>("users");
await users.Indexes.DropOneAsync(...);
}
}
The generator creates a MigrationDescriptor with:
- Type reference (
typeof(AddUserIndex)) - Version (
1.0.0) - Name (
"Add index to users") - Up collections (
["users"]) - Down collections (
["users"])
Benefits
- Smaller Package: No need to ship Microsoft.CodeAnalysis assemblies (~8MB reduction)
- Faster Startup: Migration discovery is instant (no project parsing)
- AOT/Native AOT Ready: Works with .NET Native AOT compilation
- Better Diagnostics: Duplicate version numbers are detected at compile time
- Schema Validation: Collection names are pre-extracted for schema validation without runtime source analysis
When to Use Migrations
- Rename collections
- Rename keys
- Manipulate data types
- Index manipulation
- Removing collections/data
Installation
PM> Install-Package AdaskoTheBeAsT.MongoDbMigrations
Supports:
- .NET Framework 4.7.2, 4.8, 4.8.1
- .NET 8.0, 9.0, 10.0
Quick Start
1. Create a Migration
All migrations are async to match MongoDB driver patterns:
using System.Threading.Tasks;
using AdaskoTheBeAsT.MongoDbMigrations.Abstractions;
using MongoDB.Bson;
using MongoDB.Driver;
public class AddIndexToUsers : IMigration
{
public Version Version => new Version(1, 0, 0);
public string Name => "Add index to users collection";
public async Task UpAsync(MigrationContext context)
{
var collection = context.Database.GetCollection<BsonDocument>("users");
var indexKeys = Builders<BsonDocument>.IndexKeys.Ascending("email");
await collection.Indexes.CreateOneAsync(
new CreateIndexModel<BsonDocument>(indexKeys),
cancellationToken: context.CancellationToken);
}
public async Task DownAsync(MigrationContext context)
{
var collection = context.Database.GetCollection<BsonDocument>("users");
await collection.Indexes.DropOneAsync("email_1", context.CancellationToken);
}
}
2. Run Migrations
using var engine = new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName);
var result = await engine
.UseAssembly(Assembly.GetExecutingAssembly())
.UseSchemeValidation(false)
.RunAsync();
API Reference
Configuration Methods
| Step | Methods | Description |
|---|---|---|
| 0 | new MigrationEngineBuilder() |
Create engine builder instance |
| 1 | UseSshTunnel(...), UseTls(...), UseDatabase(...) |
Database connection |
| 2 | UseAssemblyOfType(...), UseAssemblyOfType<T>(), UseAssembly(...) |
Migration classes location |
| 3 | UseSchemeValidation(...) |
Schema validation |
| 4 | UseProgressHandler(...), UseDryRun(...), UseBeforeMigration(...), UseAfterMigration(...) |
Handling features |
| 5 | RunAsync(), RunAsync(version), RollbackAsync(steps) |
Execution |
Full Example
using var engine = new MigrationEngineBuilder()
.UseSshTunnel(sshServerAddress, user, privateKeyFileStream, mongoAddress, keyFilePassPhrase) // Optional: SSH tunnel
.UseTls(cert) // Optional: TLS/SSL
.UseDatabase(connectionString, databaseName); // Required
var result = await engine
.UseAssembly(assemblyWithMigrations) // Required
.UseSchemeValidation(true, pathToCsproj) // Optional: Schema validation
.UseProgressHandler(result => Console.WriteLine(result.MigrationName)) // Optional: Progress callback
.UseBeforeMigration(migration => Console.WriteLine($"Starting: {migration.Name}")) // Optional: Before hook
.UseAfterMigration((migration, success) => Console.WriteLine($"Completed: {migration.Name}")) // Optional: After hook
.RunAsync(targetVersion, cancellationToken); // Execute (version and token are optional)
Database State Checker
// Check if database needs migrations
bool isOutdated = MongoDatabaseStateChecker.IsDatabaseOutdated(
connectionString,
databaseName,
migrationAssembly,
MongoEmulation.None);
// Throw exception if outdated
MongoDatabaseStateChecker.ThrowIfDatabaseOutdated(
connectionString,
databaseName,
migrationAssembly);
Migration Guide from v2.x to v3.x
Breaking Changes
1. Package Structure Change (New in v3.x)
Version 3.x splits the library into three packages:
| v2.x | v3.x |
|---|---|
AdaskoTheBeAsT.MongoDbMigrations (single package) |
AdaskoTheBeAsT.MongoDbMigrations.Abstractions (interfaces) |
AdaskoTheBeAsT.MongoDbMigrations.SourceGenerators (compile-time) |
|
AdaskoTheBeAsT.MongoDbMigrations (runtime engine) |
Update your project references:
<ItemGroup>
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations.Abstractions" Version="3.0.0" />
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations.SourceGenerators" Version="3.0.0"
OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations" Version="3.0.0" />
</ItemGroup>
2. Source Generator Architecture (New in v3.x)
Version 3.x introduces a source generator that replaces runtime Roslyn analysis. This means:
- Smaller deployments: No more ~8MB Microsoft.CodeAnalysis dependency at runtime
- Faster startup: Migration discovery is instant
- Compile-time validation: Duplicate version numbers are caught during build
The source generator automatically creates a MigrationRegistry class in your assembly. No action required - it works transparently.
3. Async API (Most Important)
All Run() methods have been replaced with async versions:
Before (v2.x):
var result = new MigrationEngine()
.UseDatabase(connectionString, databaseName)
.UseAssembly(assembly)
.UseSchemeValidation(false)
.Run(targetVersion);
After (v3.x):
var result = await new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName)
.UseAssembly(assembly)
.UseSchemeValidation(false)
.RunAsync(targetVersion);
4. Migration Interface Change
The Up and Down methods are now async and receive MigrationContext instead of IMongoDatabase:
Before (v2.x):
public class MyMigration : IMigration
{
public Version Version => new Version(1, 0, 0);
public string Name => "My migration";
public void Up(IMongoDatabase database)
{
database.GetCollection<BsonDocument>("users").InsertOne(...);
}
public void Down(IMongoDatabase database)
{
database.GetCollection<BsonDocument>("users").DeleteOne(...);
}
}
After (v3.x):
public class MyMigration : IMigration
{
public Version Version => new Version(1, 0, 0);
public string Name => "My migration";
public async Task UpAsync(MigrationContext context)
{
await context.Database.GetCollection<BsonDocument>("users")
.InsertOneAsync(..., cancellationToken: context.CancellationToken);
// Also available: context.Session (for transactions)
}
public async Task DownAsync(MigrationContext context)
{
await context.Database.GetCollection<BsonDocument>("users")
.DeleteOneAsync(..., cancellationToken: context.CancellationToken);
}
}
MigrationContext provides:
Database- TheIMongoDatabaseinstanceSession- OptionalIClientSessionHandlefor transaction supportCancellationToken- Token for cancellation support
5. Namespace Changes
The package namespace has changed from MongoDBMigrations to AdaskoTheBeAsT.MongoDbMigrations:
Before:
using MongoDBMigrations;
After:
using AdaskoTheBeAsT.MongoDbMigrations;
using AdaskoTheBeAsT.MongoDbMigrations.Abstractions;
6. Version Class Location
The Version class moved to the Abstractions package:
Before:
using MongoDBMigrations;
// Version was in main namespace
After:
using Version = AdaskoTheBeAsT.MongoDbMigrations.Abstractions.Version;
// Or use fully qualified name to avoid conflict with System.Version
7. MigrationEngine to MigrationEngineBuilder
The MigrationEngine class is now created via MigrationEngineBuilder:
Before (v2.x):
var result = new MigrationEngine()
.UseDatabase(...)
.Run();
After (v3.x):
using var engine = new MigrationEngineBuilder()
.UseDatabase(...);
var result = await engine.RunAsync();
Note: The engine now implements IDisposable and should be disposed after use.
Migration Checklist
- Update NuGet packages to v3.x (add all three packages as needed)
- Add
OutputItemType="Analyzer" ReferenceOutputAssembly="false"to SourceGenerators reference - Update all
usingstatements to new namespaces - Add
using Version = AdaskoTheBeAsT.MongoDbMigrations.Abstractions.Version;if needed - Change
MigrationEnginetoMigrationEngineBuilder - Change all
Run()calls toawait RunAsync() - Update migration classes:
- Change
Up(IMongoDatabase database)toasync Task UpAsync(MigrationContext context) - Change
Down(IMongoDatabase database)toasync Task DownAsync(MigrationContext context) - Replace
database.withcontext.Database. - Add
cancellationToken: context.CancellationTokento async MongoDB operations
- Change
- Update test methods to be
async Task - Add
usingstatement orDispose()call forMigrationEngineBuilder
Complete Migration Example
v2.x Migration Class:
using MongoDBMigrations;
using MongoDB.Bson;
using MongoDB.Driver;
public class AddEmailIndex : IMigration
{
public Version Version => new Version("1.0.0");
public string Name => "Add email index";
public void Up(IMongoDatabase database)
{
var collection = database.GetCollection<BsonDocument>("users");
var keys = Builders<BsonDocument>.IndexKeys.Ascending("email");
collection.Indexes.CreateOne(new CreateIndexModel<BsonDocument>(keys));
}
public void Down(IMongoDatabase database)
{
var collection = database.GetCollection<BsonDocument>("users");
collection.Indexes.DropOne("email_1");
}
}
v3.x Migration Class:
using System.Threading.Tasks;
using AdaskoTheBeAsT.MongoDbMigrations.Abstractions;
using MongoDB.Bson;
using MongoDB.Driver;
public class AddEmailIndex : IMigration
{
public Version Version => new Version(1, 0, 0);
public string Name => "Add email index";
public async Task UpAsync(MigrationContext context)
{
var collection = context.Database.GetCollection<BsonDocument>("users");
var keys = Builders<BsonDocument>.IndexKeys.Ascending("email");
await collection.Indexes.CreateOneAsync(
new CreateIndexModel<BsonDocument>(keys),
cancellationToken: context.CancellationToken);
}
public async Task DownAsync(MigrationContext context)
{
var collection = context.Database.GetCollection<BsonDocument>("users");
await collection.Indexes.DropOneAsync("email_1", context.CancellationToken);
}
}
v2.x Runner:
var result = new MigrationEngine()
.UseDatabase(connectionString, databaseName)
.UseAssembly(typeof(AddEmailIndex).Assembly)
.UseSchemeValidation(false)
.Run();
v3.x Runner:
using var engine = new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName);
var result = await engine
.UseAssembly(typeof(AddEmailIndex).Assembly)
.UseSchemeValidation(false)
.RunAsync();
Azure CosmosDB Support
For Azure CosmosDB (MongoDB API), use the MongoEmulation.AzureCosmos option:
using var engine = new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName, MongoEmulation.AzureCosmos);
var result = await engine
.UseAssembly(assembly)
.RunAsync();
Note: If you already have migrations from an earlier version, ensure you have an ascending index on the applied field in the _migrations collection.
AWS DocumentDB Support
AWS DocumentDB is supported out of the box.
CI/CD Integration
Use the AdaskoTheBeAsT.MongoDbMigrations.ps1 script for CI/CD pipelines. This allows backup and rollback on failure.
Set-Alias mongodump <path_to_mongodump>
Set-Alias mongorestore <path_to_mongorestore>
| Parameter | Description |
|---|---|
connectionString |
Database connection string |
databaseName |
Name of the database |
backupLocation |
Folder for backup |
migrationsAssemblyPath |
Path to assembly with migrations |
Best Practices
- Use
{version}_{migrationName}.csnaming pattern (e.g.,1_0_0_AddUserIndex.cs) - Keep migrations in non-production assemblies
- Keep migrations simple and focused
- Don't couple migrations to domain types
- Use
BsonDocumentor MongoDB JavaScript API - Add application startup check for database version
- Write tests for migrations using
IgnoreMigrationattribute during development - Automate migration deployment
Transaction Support
Enable transaction support for migration batches:
using var engine = new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName)
.UseTransaction();
var result = await engine
.UseAssembly(assembly)
.RunAsync();
Note: Transaction support requires MongoDB 4.0+ with replica set or sharded cluster.
Rollback Support
Rollback migrations by a specified number of steps:
using var engine = new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName);
// Rollback 2 migration steps
var result = await engine
.UseAssembly(assembly)
.RollbackAsync(2);
Dry Run Mode
Test migrations without applying changes:
using var engine = new MigrationEngineBuilder()
.UseDatabase(connectionString, databaseName);
var result = await engine
.UseAssembly(assembly)
.UseDryRun(true)
.RunAsync(targetVersion);
// result.IsDryRun will be true
// No changes are applied to the database
Acknowledgments
This library is based on the excellent work of:
- Artur Osmokiesku - Original author of the MongoDBMigrations library
- Ruxo Zheng (ruxo) - Maintainer of the MongoDBMigrationsRZ fork with .NET updates and session support
Why This Fork?
While the original MongoDBMigrations library is excellent, it has some limitations that this fork addresses:
| Aspect | Original Library | This Library (v3.x) |
|---|---|---|
| Migration Discovery | Runtime Roslyn analysis (~8MB dependency) | Compile-time source generators |
| Package Size | Large (includes Microsoft.CodeAnalysis) | Minimal (no CodeAnalysis at runtime) |
| Startup Time | Slow (parses source files at runtime) | Fast (pre-computed at build) |
| AOT Compatibility | Not compatible | Fully compatible with Native AOT |
| Error Detection | Runtime failures | Compile-time diagnostics |
| API Style | Synchronous | Fully async/await |
| Transaction Support | Limited | Full session/transaction support via MigrationContext |
| Cancellation | Not supported | Built-in CancellationToken support |
Key Innovations
Source Generator Architecture: Collection names, versions, and migration metadata are extracted at compile time, eliminating the need for runtime Roslyn analysis.
Modern Async API: All migration methods use
async Taskpatterns, allowing proper async/await usage with MongoDB driver operations.MigrationContext: Provides access to
IMongoDatabase,IClientSessionHandle(for transactions), andCancellationTokenin a single context object.Package Separation: Split into three packages (Abstractions, SourceGenerators, Runtime) for optimal deployment scenarios.
Thank you to the original authors for creating such a useful library for the .NET MongoDB community!
License
Licensed under MIT.
| 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. |
| .NET Framework | net472 is compatible. net48 is compatible. net481 is compatible. |
-
.NETFramework 4.7.2
- AdaskoTheBeAsT.MongoDbMigrations.Abstractions (>= 3.0.0)
- MongoDB.Bson (>= 3.5.2)
- MongoDB.Driver (>= 3.5.2)
- SSH.NET (>= 2025.1.0)
-
.NETFramework 4.8
- AdaskoTheBeAsT.MongoDbMigrations.Abstractions (>= 3.0.0)
- MongoDB.Bson (>= 3.5.2)
- MongoDB.Driver (>= 3.5.2)
- SSH.NET (>= 2025.1.0)
-
.NETFramework 4.8.1
- AdaskoTheBeAsT.MongoDbMigrations.Abstractions (>= 3.0.0)
- MongoDB.Bson (>= 3.5.2)
- MongoDB.Driver (>= 3.5.2)
- SSH.NET (>= 2025.1.0)
-
net10.0
- AdaskoTheBeAsT.MongoDbMigrations.Abstractions (>= 3.0.0)
- MongoDB.Bson (>= 3.5.2)
- MongoDB.Driver (>= 3.5.2)
- SSH.NET (>= 2025.1.0)
-
net8.0
- AdaskoTheBeAsT.MongoDbMigrations.Abstractions (>= 3.0.0)
- MongoDB.Bson (>= 3.5.2)
- MongoDB.Driver (>= 3.5.2)
- SSH.NET (>= 2025.1.0)
-
net9.0
- AdaskoTheBeAsT.MongoDbMigrations.Abstractions (>= 3.0.0)
- MongoDB.Bson (>= 3.5.2)
- MongoDB.Driver (>= 3.5.2)
- SSH.NET (>= 2025.1.0)
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 |
|---|---|---|
| 3.0.0 | 10,140 | 1/2/2026 |