AdaskoTheBeAsT.MongoDbMigrations 3.0.0

dotnet add package AdaskoTheBeAsT.MongoDbMigrations --version 3.0.0
                    
NuGet\Install-Package AdaskoTheBeAsT.MongoDbMigrations -Version 3.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AdaskoTheBeAsT.MongoDbMigrations" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="AdaskoTheBeAsT.MongoDbMigrations" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AdaskoTheBeAsT.MongoDbMigrations --version 3.0.0
                    
#r "nuget: AdaskoTheBeAsT.MongoDbMigrations, 3.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package AdaskoTheBeAsT.MongoDbMigrations@3.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=AdaskoTheBeAsT.MongoDbMigrations&version=3.0.0
                    
Install as a Cake Addin
#tool nuget:?package=AdaskoTheBeAsT.MongoDbMigrations&version=3.0.0
                    
Install as a Cake Tool

AdaskoTheBeAsT.MongoDbMigrations

NuGet

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

  1. At Compile Time: The source generator scans your migration classes, extracts version info, names, and MongoDB collection names used in UpAsync/DownAsync methods.

  2. Generated Registry: A MigrationRegistry class 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() => ...
}
  1. At Runtime: The MigrationManager automatically 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

  1. Rename collections
  2. Rename keys
  3. Manipulate data types
  4. Index manipulation
  5. 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 - The IMongoDatabase instance
  • Session - Optional IClientSessionHandle for transaction support
  • CancellationToken - 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 using statements to new namespaces
  • Add using Version = AdaskoTheBeAsT.MongoDbMigrations.Abstractions.Version; if needed
  • Change MigrationEngine to MigrationEngineBuilder
  • Change all Run() calls to await RunAsync()
  • Update migration classes:
    • Change Up(IMongoDatabase database) to async Task UpAsync(MigrationContext context)
    • Change Down(IMongoDatabase database) to async Task DownAsync(MigrationContext context)
    • Replace database. with context.Database.
    • Add cancellationToken: context.CancellationToken to async MongoDB operations
  • Update test methods to be async Task
  • Add using statement or Dispose() call for MigrationEngineBuilder

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

  1. Use {version}_{migrationName}.cs naming pattern (e.g., 1_0_0_AddUserIndex.cs)
  2. Keep migrations in non-production assemblies
  3. Keep migrations simple and focused
  4. Don't couple migrations to domain types
  5. Use BsonDocument or MongoDB JavaScript API
  6. Add application startup check for database version
  7. Write tests for migrations using IgnoreMigration attribute during development
  8. 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

  1. Source Generator Architecture: Collection names, versions, and migration metadata are extracted at compile time, eliminating the need for runtime Roslyn analysis.

  2. Modern Async API: All migration methods use async Task patterns, allowing proper async/await usage with MongoDB driver operations.

  3. MigrationContext: Provides access to IMongoDatabase, IClientSessionHandle (for transactions), and CancellationToken in a single context object.

  4. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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