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.

Prerequisites

What You’ll Learn

  • Which migration/seeding events are emitted
  • How to subscribe and route event streams
  • How to use lifecycle events for observability and auditing

Step Outcome

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

  • Subscribe to migration/seeding lifecycle streams once at startup
  • Route failures and progress into logs/metrics/traces
  • Correlate migration/seeding events with runtime query telemetry
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