Skip to main content

Running Migrations

Snippet context

These snippets are split by step (entries → ledger → runner → apply/rollback) so you can copy just the part you need.

Programmatic Usage

Use MigrationRunner to run migrations in code:

1) Define entries

  final entries = [
MigrationEntry(
id: MigrationId.parse('m_20241201000000_create_users_table'),
migration: const CreateUsersTable(),
),
MigrationEntry(
id: MigrationId.parse('m_20241201000100_create_posts_table'),
migration: const CreatePostsTable(),
),
];

// Build descriptors (sorted by timestamp)
final descriptors = MigrationEntry.buildDescriptors(entries);

2) Create a ledger

  // Create ledger to track applied migrations
final ledger = SqlMigrationLedger(driver, tableName: '_orm_migrations');
await ledger.ensureInitialized();

3) Create the runner

  // Create runner
final runner = MigrationRunner(
schemaDriver: driver,
ledger: ledger,
migrations: descriptors,
);

4) Apply / rollback

  // Apply all pending migrations
await runner.applyAll();

// Or apply with a limit
await runner.applyAll(limit: 5);
  // Rollback last batch
await runner.rollback();

// Rollback multiple batches
await runner.rollback(steps: 3);

5) Inspect status

  // Check status
final statuses = await runner.status();
for (final status in statuses) {
print('${status.id}: ${status.isApplied ? 'Applied' : 'Pending'}');
}

Ledger API

The ledger tracks which migrations have been applied:

Future<void> ledgerApiExample(DriverAdapter driver) async {
final ledger = SqlMigrationLedger(driver, tableName: 'orm_migrations');
await ledger.ensureInitialized();

// Get next batch number
final batch = await ledger.nextBatchNumber();

// Log applied migration
// await ledger.logApplied(
// descriptor,
// DateTime.now().toUtc(),
// batch: batch,
// );

// Using ConnectionManager
// final managedLedger = SqlMigrationLedger.managed(
// connectionName: 'primary',
// tableName: 'orm_migrations',
// );
// await managedLedger.ensureInitialized();
}

Migration Registry

The CLI maintains a registry file to track available migrations:

Each migration registers an id + migration instance:

final List<MigrationEntry> _entries = [
// <ORM-MIGRATION-REGISTRY>
// </ORM-MIGRATION-REGISTRY>
];

The marker comments allow the CLI to automatically insert new migrations.

Troubleshooting

Migration Already Applied

Error: Migration X has already been applied

Use migrate:status to check applied migrations. Roll back first if you need to re-run.

Checksum Mismatch

Error: Migration checksum doesn't match recorded value

A migration was modified after being applied. Either:

  • Revert changes to the migration file
  • Create a new migration with the changes

Foreign Key Constraint Failed

Ensure:

  • Parent tables are created before child tables
  • Child tables are dropped before parent tables
  • Foreign key columns match the referenced column type