Fluens.Migrations
0.7.9
dotnet add package Fluens.Migrations --version 0.7.9
NuGet\Install-Package Fluens.Migrations -Version 0.7.9
<PackageReference Include="Fluens.Migrations" Version="0.7.9" />
<PackageVersion Include="Fluens.Migrations" Version="0.7.9" />
<PackageReference Include="Fluens.Migrations" />
paket add Fluens.Migrations --version 0.7.9
#r "nuget: Fluens.Migrations, 0.7.9"
#:package Fluens.Migrations@0.7.9
#addin nuget:?package=Fluens.Migrations&version=0.7.9
#tool nuget:?package=Fluens.Migrations&version=0.7.9
Fluens.Migrations
Provider-neutral FluentMigrator base classes and helpers for inbox/outbox tables, dead letters, HiLo sequences, and auditable/deletable columns. Zero Fluens dependencies.
Installation
dotnet add package Fluens.Migrations
# Plus exactly one provider package:
dotnet add package Fluens.Migrations.PostgreSql
# or
dotnet add package Fluens.Migrations.SqlServer
Usage
Runner registration
The provider is opted into from the AddFluens callback on FluentMigrator's own ConfigureRunner pipeline —
never through a bespoke top-level method. rb.AddPostgres() / rb.AddSqlServer() (FluentMigrator's own
provider registration) and .AddFluens(f => f.AddPostgres()) / .AddFluens(f => f.AddSqlServer()) (the
Fluens conventions opt-in) are distinct extension targets — no ambiguity:
services.AddFluentMigratorCore()
.ConfigureRunner(rb => rb
.AddPostgres() // FluentMigrator's own provider registration
.WithGlobalConnectionString(connectionString)
.ScanIn(typeof(CreateOrdersSchema).Assembly).For.Migrations()
.AddFluens(f => f.AddPostgres())); // Fluens provider-conventions opt-in
Migration classes
Every FluensMigration subclass needs a forwarding constructor — Conventions is resolved by FluentMigrator's
own constructor-injection support when the runner instantiates the migration, so a single, unchanged
subclass creates the same schema on both providers:
public class CreateOrdersSchema : FluensMigration
{
public CreateOrdersSchema(IMigrationProviderConventions conventions) : base(conventions) { }
public override void Up()
{
Create.Schema("orders");
Create.Table("orders").InSchema("orders")
.WithColumn("id").AsGuid().PrimaryKey()
.WithColumn("number").AsString(50).NotNullable()
.WithColumn("total").AsDecimal().NotNullable()
.WithAuditableAndDeletableColumns()
.WithVersionColumn();
CreateMessagingTables("orders"); // outbox + inbox + dead_letters
CreateHiLoSequence("orders_hilo", "orders");
}
public override void Down()
{
DeleteMessagingTables("orders");
DeleteHiLoSequence("orders_hilo", "orders");
Delete.Table("orders").InSchema("orders");
}
}
Helpers: WithAuditableColumns(), WithDeletableColumn(), WithAuditableAndDeletableColumns(), WithVersionColumn(),
CreateOutboxTable(), CreateOutboxDeliveryTable(), CreateInboxTable(), CreateIngressOutboxTable(), CreateDeadLettersTable(),
CreateMessagingTables(), CreateHiLoSequence(), DeleteOutboxTable(), DeleteOutboxDeliveryTable(), DeleteInboxTable(),
DeleteIngressOutboxTable(), DeleteDeadLettersTable(), DeleteMessagingTables(), DeleteHiLoSequence().
Messaging schema (ADR 20260530000001 / ADR 20260530000002 / ADR 20260729000001)
All four messaging tables carry the serialized envelope blob (non-nullable; ADR 20260530000001 — replaces the
bare context column) plus the denormalized routing columns (partition_key, priority, and on outbox
also available_at) so the partial pending indexes can sort / filter on real columns. Each table has a
partial pending index emitted via Conventions.ApplyFilter(<index>.WithOptions(), "<predicate>") — the
registered provider package's .Filter(...) extension — so the hot fetch scans only in-flight rows:
outbox— the terminal marker issent_at(renamed from the legacypublished_atflag; ADR 20260530000002). Message-TTL columnsexpires_at(non-nullable, computed from(available_at ?? created_at)at write) andexpired_at(nullable, set in place on TTL expiry — the row is never deleted, only marked). Also carriesmint_seq(bigint, non-nullable, default0— a provider-neutral monotonic mint-time key derived fromid's embedded GUIDv7 timestamp; ADR 20260729000001). Partialix_outbox_pending(WHERE sent_at IS NULL) over(sent_at, priority DESC, mint_seq).inbox— composite primary key(message_id, handler_type)(one row per subscribing handler). Also carriesmint_seq(same shape asoutbox, derived frommessage_id) and addsnext_retry_at(stage-2 retry schedule). Partialix_inbox_pending(WHERE processed_at IS NULL) over(handler_type, partition_key, priority DESC, mint_seq).ingress_outbox— primary keymessage_id(boundary dedup). Partialix_ingress_pending(WHERE processed_at IS NULL) overreceived_at.dead_letters— adds the why-columnshandler_type,partition_key,failure_code,exception_type,attempt_history(Conventions.JsonColumnType—jsonbon PostgreSQL,nvarchar(max)on SQL Server), and the replay markerreplayed_at.
No upgrade (AddColumn) migration ships for mint_seq — CreateOutboxTable/CreateInboxTable are
create-table helpers only, so a consumer upgrading an already-deployed schema authors their own
AddColumn("mint_seq").AsInt64().NotNullable().WithDefaultValue(0) step plus the corresponding index
rebuild (ADR 20260729000001).
CreateOutboxDeliveryTable(schema) creates the per-destination delivery table (one row per
(outbox_id, destination_app) pair) with a unique ix_outbox_delivery_outbox_dest index on
(outbox_id, destination_app) for re-fan-out idempotency, an ix_outbox_delivery_destination_app index, and
the partial ix_delivery_pending (WHERE delivered_at IS NULL AND expired_at IS NULL) over
(expires_at, destination_app); CreateMessagingTables creates it alongside outbox/inbox in the module
schema. CreateIngressOutboxTable(schema = "shared") creates the single staging table into which a
peer-delivered batch is written atomically before acking.
Provider-specific column types
Use Fluens.Migrations.PostgreSql or Fluens.Migrations.SqlServer for provider-specific column types —
independent of which IMigrationProviderConventions is registered for the run:
using Fluens.Migrations.PostgreSql; // AsCitext(), AsTimestampTz()
Create.Table("customers").InSchema("orders")
.WithColumn("id").AsInt32().PrimaryKey().Identity()
.WithColumn("email").AsCitext().NotNullable() // case-insensitive text
.WithColumn("created_at").AsTimestampTz().NotNullable(); // timestamp with time zone
using Fluens.Migrations.SqlServer; // AsNVarCharMax(), AsDateTimeOffset2()
Create.Table("customers").InSchema("orders")
.WithColumn("id").AsInt32().PrimaryKey().Identity()
.WithColumn("notes").AsNVarCharMax().Nullable() // unbounded Unicode text
.WithColumn("created_at").AsDateTimeOffset2().NotNullable(); // timestamp with time zone
Helpers: Fluens.Migrations.PostgreSql.AsCitext() / .AsTimestampTz(); Fluens.Migrations.SqlServer.AsNVarCharMax() / .AsDateTimeOffset2().
License
This project is licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- FluentMigrator (>= 8.0.1)
- FluentMigrator.Runner.Core (>= 8.0.1)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Fluens.Migrations:
| Package | Downloads |
|---|---|
|
Fluens.Migrations.SqlServer
SQL Server provider for Fluens.Migrations — nvarchar(max) attempt_history column type, datetimeoffset column helper, and FluentMigrator.SqlServer partial-index filters. Opt in via rb.AddFluens(f => f.AddSqlServer()). |
|
|
Fluens.Migrations.PostgreSql
PostgreSQL provider for Fluens.Migrations — jsonb attempt_history column type, citext/timestamptz column helpers, and FluentMigrator.Postgres partial-index filters. Opt in via rb.AddFluens(f => f.AddPostgres()). |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.9 | 39 | 9/11/2026 |
| 0.7.8 | 46 | 9/10/2026 |
| 0.7.7 | 45 | 9/10/2026 |
| 0.7.6 | 158 | 7/1/2026 |
| 0.7.5 | 135 | 6/22/2026 |
| 0.7.4 | 145 | 6/18/2026 |
| 0.7.2 | 119 | 6/18/2026 |
| 0.7.1 | 134 | 6/18/2026 |
| 0.6.6 | 269 | 3/11/2026 |
| 0.6.5 | 119 | 3/4/2026 |
| 0.6.4 | 111 | 3/4/2026 |
| 0.6.3 | 125 | 3/3/2026 |
| 0.6.2 | 125 | 3/2/2026 |
| 0.6.1 | 121 | 3/2/2026 |
| 0.6.0 | 116 | 3/1/2026 |
| 0.5.7 | 131 | 3/1/2026 |
| 0.5.6 | 120 | 3/1/2026 |
| 0.5.5 | 121 | 2/28/2026 |
| 0.5.4 | 123 | 2/28/2026 |
| 0.5.3 | 126 | 2/27/2026 |