Skip to main content

Migration & Seeding Events

Migrations and seeders emit structured events through the shared EventBus. Subscribe once to stream progress to logs, metrics, or tracing.

:::note Snippet context The snippets below are split into “subscribe” and “run” pieces so you can reuse the listener wiring in your own bootstrap code. :::

Migration Lifecycle

Events (all emitted by MigrationRunner):

  • MigrationBatchStartedEvent / MigrationBatchCompletedEvent
  • MigrationStartedEvent / MigrationCompletedEvent
  • MigrationFailedEvent (includes error and stackTrace)

Example listener + runner setup:

bus.on<MigrationBatchStartedEvent>((event) {
print('Migration batch ${event.batch} started');
});

bus.on<MigrationStartedEvent>((event) {
print('Applying ${event.id}');
});

bus.on<MigrationCompletedEvent>((event) {
print('Applied ${event.id} in ${event.duration.inMilliseconds}ms');
});

bus.on<MigrationFailedEvent>((event) {
print('Failed ${event.id}: ${event.error}');
});

Seeding Lifecycle

Events (emitted by SeederRunner and database seeders):

  • SeedingStartedEvent / SeedingCompletedEvent
  • SeederStartedEvent / SeederCompletedEvent
  • SeederFailedEvent

Example with a custom seeder and event hooks:

Define a seeder

class DemoUserSeeder extends DatabaseSeeder {
DemoUserSeeder(super.connection);


Future<void> run() async {
await seed<User>([
{'name': 'Demo', 'email': 'demo@example.com'},
]);
}
}
bus.on<SeedingStartedEvent>((event) {
print('Seeding started: ${event.seederNames.join(', ')}');
});

bus.on<SeederStartedEvent>((event) {
print('Running seeder ${event.seederName} (${event.index}/${event.total})');
});

bus.on<SeederCompletedEvent>((event) {
print('Seeder ${event.seederName} finished in ${event.duration}');
});

bus.on<SeederFailedEvent>((event) {
print('Seeder ${event.seederName} failed: ${event.error}');
});

bus.on<SeedingCompletedEvent>((event) {
print('Seeding complete (${event.count} seeders) in ${event.duration}');
});

Tips:

  • Use the same EventBus for migrations, seeders, and runtime queries to correlate logs.
  • SeederFailedEvent fires before the error is rethrown—log here, then let your process fail.
  • Combine with pretend: true on SeederRunner.run to capture SQL without mutating the database.

Verify Event Stream

  1. Run one migration batch and confirm batch + per-migration events are emitted.
  2. Run one seed flow and confirm start/completion/failure hooks.
  3. Confirm failed events include enough context for alerting.

Read This Next