A versioned, journaled migration framework for .NET that supports relational and NoSQL databases through a single, consistent API.
Documentation: https://stillpoint-software.github.io/hyperbee.migrations/
Database schema and data evolve over the life of an application. Hyperbee.Migrations gives you a structured, version-controlled way to evolve them across every environment -- local, test, staging, production -- with the same discipline you bring to source code. Migrations live in your repo as C# classes (or as embedded resource files), are discovered by reflection at runtime, and execute exactly once per environment.
v3.0 adds migration squashing across all five providers, plus the tooling and discovery surface that supports it:
- Migration squashing. Collapse a long run of historical
migrations
[N..M]into a single equivalent squash migration. Mature environments auto-mark the squash via theReplacesgraph (no re-run); fresh installs run the squash body. Squashes are up-only and carry a content checksum +Kind/Replacesledger metadata. - The
hyperbee-migrationsCLI. Generates squash artifacts against an ephemeral, topology-matched container, runs a verification round, and emits the squash body + sidecar metadata + summary. Also hosts therecover from-mid-rangeverb for the documented mid-range recovery path. The CLI references zero provider packages -- it discovers providers through the migration assembly's reference closure. - Five
.Squashprovider packages.Hyperbee.Migrations.Providers.<P>.Squash(Postgres, Aerospike, MongoDB, OpenSearch, Couchbase) each implement the sharedISquashProvidercontract (provider-specific snapshot capture + canonicalization + verification). Install the.Squashpackage alongside the provider package to enablehyperbee-migrations squash --provider <p>for that store. IMigrationHostdiscovery. A migration project exposes exactly oneIMigrationHostthat builds a configured service provider for an arbitrary connection. The CLI, the recovery verb, and the runner all consume the same host through a single reflection scan -- the v1 Postgres-only static-method convention is gone.
Upgrading from v2: existing v2 migrations continue to work unchanged; squash is additive. See the v2 -> v3 upgrade guide and the squashing migrations guide.
| Provider | Package | Statement format | Locking |
|---|---|---|---|
| Aerospike | Hyperbee.Migrations.Providers.Aerospike |
AQL-like | CREATE_ONLY record + TTL |
| Couchbase | Hyperbee.Migrations.Providers.Couchbase |
N1QL | Couchbase.Extensions.Locks |
| MongoDB | Hyperbee.Migrations.Providers.MongoDB |
shell-like | document conditional write |
| OpenSearch | Hyperbee.Migrations.Providers.OpenSearch |
OpenSearch DSL | op_type=create + realtime GET |
| PostgreSQL | Hyperbee.Migrations.Providers.Postgres |
raw .sql files |
session-level advisory lock |
Targets .NET 8, 9, and 10. Each provider package is shipped independently on NuGet.
dotnet add package Hyperbee.Migrations.Providers.PostgresOr whichever provider matches your store. The core Hyperbee.Migrations library is referenced transitively.
// Program.cs
using Hyperbee.Migrations.Providers.Postgres;
var builder = WebApplication.CreateBuilder( args );
// Register the Npgsql data source the migration runner reads from.
builder.Services.AddNpgsqlDataSource( builder.Configuration.GetConnectionString( "Migrations" ) );
builder.Services.AddPostgresMigrations( opts =>
{
opts.SchemaName = "migration"; // ledger schema (default: "migration")
// LockingEnabled defaults to true in v3.0 (production-safe). Set false
// explicitly only for dev/test fixtures that intentionally race.
} );
var app = builder.Build();
using ( var scope = app.Services.CreateScope() )
{
// Single-provider host: resolve the typed runner. Resolving the base
// MigrationRunner also works in single-provider hosts, but the typed
// runner is the documented entry point and the only one that works in
// multi-provider hosts (a multi-provider host throws on
// GetRequiredService<MigrationRunner>() to prevent silently routing to
// the wrong provider).
var runner = scope.ServiceProvider.GetRequiredService<PostgresMigrationRunner>();
await runner.RunAsync( app.Lifetime.ApplicationStopping );
}
app.Run();Multi-provider hosts. When you call more than one
Add{Provider}Migrationson the same service collection (e.g. one app applies Postgres + MongoDB migrations),GetRequiredService<MigrationRunner>()throws to prevent silently routing to the wrong provider. Resolve the typed runner directly:PostgresMigrationRunner,MongoDBMigrationRunner,CouchbaseMigrationRunner,OpenSearchMigrationRunner,AerospikeMigrationRunner. See multi-provider hosts for the full pattern.
A migration is a class:
using Hyperbee.Migrations;
[Migration( 20260101_001 )]
public class CreateUsersTable( PostgresResourceRunner<CreateUsersTable> runner ) : Migration
{
public override Task UpAsync( CancellationToken ct = default )
=> runner.AllSqlFromAsync( ct );
}The companion resource file Resources/20260101_001_CreateUsersTable.sql ships in the assembly via <EmbeddedResource>.
For detailed walk-throughs by provider, see the documentation site:
A single application can register migrations for more than one provider:
builder.Services
.AddPostgresMigrations( opts => { /* ... */ } )
.AddMongoDBMigrations( opts => { /* ... */ } );
// Resolve typed runners; the base MigrationRunner resolution throws in
// multi-provider hosts to prevent silent shadowing.
var pg = sp.GetRequiredService<PostgresMigrationRunner>();
var mg = sp.GetRequiredService<MongoDBMigrationRunner>();See Multi-Provider Hosts for the full pattern, failure-isolation samples, and the expand/contract recipe for cross-store changes.
| Path | Contents |
|---|---|
src/Hyperbee.Migrations/ |
Core: runner, options, record-store contract, conventions, resource helpers |
src/Hyperbee.Migrations.Providers.*/ |
Per-provider implementations |
runners/Hyperbee.MigrationRunner.*/ |
Per-provider standalone runner executables (Docker-ready) |
runners/samples/ |
Working samples per provider |
docs/site/ |
Jekyll documentation source (just-the-docs) |
docs/decisions/ |
Architecture Decision Records |
tests/ |
Unit + Testcontainers integration tests |
| Concepts & guides | https://stillpoint-software.github.io/hyperbee.migrations/ |
| Operator guides | docs/guides/ |
| Changelog | CHANGELOG.md |
Requires .NET 8, 9, and 10 SDKs (the solution multi-targets all three for compatibility testing).
git clone https://github.com/Stillpoint-Software/hyperbee.migrations.git
cd hyperbee.migrations
dotnet build Hyperbee.Migrations.slnx -c Release
dotnet test Hyperbee.Migrations.slnx -c ReleaseIntegration tests use Testcontainers and require a Docker engine. They are gated behind #if INTEGRATIONS; enable with -p:EnableIntegrationTests=true.
The framework API draws on prior art in the .NET migration space:
- Fluent Migrator
- Raven Migrations
- DbUp
- Cronos -- cron expression support
- Couchbase .NET Client -- Couchbase connectivity and DI extensions
- Parlot -- statement parsers across all providers
See CONTRIBUTING.md for the build/test/PR flow. We use a trunk-based GitHub flow; please open an issue to discuss substantial changes before sending a PR.
Released under the MIT License.