Skip to main content

IMigration

The core interface that every migration class must implement. Defined in the Cosmigrator namespace.

namespace Cosmigrator;

public interface IMigration
{
string Id { get; }
string Name { get; }
string ContainerName { get; }
object? DefaultValue => null;

Task UpAsync(Container container, CosmosClient client);
Task DownAsync(Container container, CosmosClient client);
}

Properties

PropertyTypeDescription
IdstringUnique identifier used for ordering and history tracking. Convention: "YYYYMMDD_NNNNNN"
NamestringHuman-readable name describing what the migration does
ContainerNamestringName of the target Cosmos DB container this migration operates on
DefaultValueobject?Optional default value for property additions. Default implementation returns null

Methods

MethodReturnsDescription
UpAsync(Container, CosmosClient)TaskApplies the migration forward. Receives the target container and the Cosmos client for advanced operations
DownAsync(Container, CosmosClient)TaskRolls back the migration. Receives the same parameters as UpAsync

Parameters

UpAsync / DownAsync

ParameterTypeDescription
containerMicrosoft.Azure.Cosmos.ContainerThe target container resolved from ContainerName
clientMicrosoft.Azure.Cosmos.CosmosClientThe Cosmos client — use for operations that need database-level access (e.g., creating containers)

Id convention

The Id property determines execution order. Migrations are sorted lexicographically by Id, so use a timestamp-based format:

YYYYMMDD_NNNNNN

Examples:

  • "20250101_000001" — first migration
  • "20250101_000002" — second migration
  • "20250215_000001" — migration added on Feb 15

DefaultValue

DefaultValue has a default interface implementation of null. Override it to specify a default when adding new properties:

public object? DefaultValue => 0;           // int
public object? DefaultValue => ""; // string
public object? DefaultValue => Guid.Empty; // Guid
public object? DefaultValue => null; // null (default)

Example

public class _20250219_000001_AddEmailToUsers : IMigration
{
public string Id => "20250219_000001";
public string Name => "AddEmailToUsers";
public string ContainerName => "Users";
public object? DefaultValue => "";

public async Task UpAsync(Container container, CosmosClient client)
{
using var loggerFactory = LoggerFactory.Create(b => b.AddConsole());
var helper = new BulkOperationHelper(
loggerFactory.CreateLogger<BulkOperationHelper>());

var docs = await helper.ReadDocumentsAsync(
container,
"SELECT * FROM c WHERE NOT IS_DEFINED(c.email)");

foreach (var doc in docs)
doc["email"] = JsonValue.Create(DefaultValue);

if (docs.Count > 0)
await helper.BulkUpsertAsync(container, docs);
}

public async Task DownAsync(Container container, CosmosClient client)
{
using var loggerFactory = LoggerFactory.Create(b => b.AddConsole());
var helper = new BulkOperationHelper(
loggerFactory.CreateLogger<BulkOperationHelper>());

var docs = await helper.ReadDocumentsAsync(
container,
"SELECT * FROM c WHERE IS_DEFINED(c.email)");

foreach (var doc in docs)
doc.Remove("email");

if (docs.Count > 0)
await helper.BulkUpsertAsync(container, docs);
}
}