Skip to main content

Running Migrations

Prerequisites

What You’ll Learn

  • How to apply/rollback migrations programmatically
  • How migration ledger state is tracked
  • How to inspect migration status safely

Step Outcome

By the end of this page, you should be able to:

  • Apply/rollback migrations predictably
  • Inspect migration ledger state before/after deploys
  • Diagnose common migration failures quickly
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'}');
}

CLI Workflow (Most Common)

dart run ormed_cli:ormed migrate
dart run ormed_cli:ormed migrate --pretend
dart run ormed_cli:ormed migrate:rollback --steps 1
dart run ormed_cli:ormed migrate:status

Use --pretend before risky deploys to inspect generated SQL without applying changes.

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

Deployment Tip

Run migration status checks in CI/CD before and after applying migrations so drift is visible immediately.

Read This Next