Skip to content

Seeders

Seeders provide an application-layer CLI for populating your database outside of tests. They use dependency injection, giving them access to your services, repositories, and any other provider in your module tree.

Seeders are part of the core stratal package and run as built-in Quarry CLI commands.

Extend the Seeder base class from stratal/seeder and implement the run() method. Use constructor injection to access your services:

import { Seeder } from 'stratal/seeder'
import { inject, Transient } from 'stratal/di'
import { NotesService } from '../notes/notes.service'
@Transient()
export class NotesSeeder extends Seeder {
constructor(@inject(NotesService) private readonly notesService: NotesService) {
super()
}
async run(): Promise<void> {
const notes = [
{ title: 'Welcome', content: 'This note was created by a seeder' },
{ title: 'Getting Started', content: 'Seeders populate your app with initial data' },
{ title: 'Stratal', content: 'A modular Cloudflare Workers framework' },
]
for (const note of notes) {
this.notesService.create(note)
}
}
}

Add the seeder to a module’s providers array:

import { Module } from 'stratal/module'
import { NotesSeeder } from './seeders/notes.seeder'
@Module({
providers: [NotesSeeder],
})
export class NotesModule {}

Seeders run via the Quarry CLI using the built-in db:seed and db:seed:list commands.

Pass the seeder class name to db:seed:

Terminal window
npx quarry db:seed NotesSeeder
Terminal window
npx quarry db:seed --all
Terminal window
npx quarry db:seed:list

Preview which seeders would run without executing them:

Terminal window
npx quarry db:seed --all --dry-run

Seeders are identified by their class name when using the db:seed command:

Class nameCLI usage
NotesSeedernpx quarry db:seed NotesSeeder
RolePermissionsSeedernpx quarry db:seed RolePermissionsSeeder
InitialDataSeedernpx quarry db:seed InitialDataSeeder

Use this.call() to invoke another seeder from within a seeder:

import { Seeder } from 'stratal/seeder'
import { Transient } from 'stratal/di'
import { UserSeeder } from './user.seeder'
import { PostSeeder } from './post.seeder'
@Transient()
export class DatabaseSeeder extends Seeder {
async run(): Promise<void> {
await this.call(UserSeeder)
await this.call(PostSeeder)
}
}

Seeders are automatically discovered from the module tree. Any class that extends Seeder and is listed in a module’s providers array will be found by the CLI. Only bare class providers are scanned — value, factory, and existing providers are skipped.

The Quarry CLI uses Wrangler’s getPlatformProxy() to obtain your Cloudflare bindings (D1, KV, R2, etc.) locally. It then bootstraps your module tree, discovers all classes that extend Seeder, and executes their run() methods inside a request scope.

Seeders pair naturally with factories for generating realistic data:

import { Seeder } from 'stratal/seeder'
import { inject, DI_TOKENS, Transient } from 'stratal/di'
import type { DatabaseService } from '@stratal/framework/database'
import { UserFactory } from './user.factory'
import { PostFactory } from './post.factory'
@Transient()
export class DemoDataSeeder extends Seeder {
constructor(
@inject(DI_TOKENS.Database) private readonly db: DatabaseService,
) {
super()
}
async run(): Promise<void> {
const users = await new UserFactory().count(5).createManyAndReturn(this.db)
for (const user of users) {
await new PostFactory()
.state(attrs => ({ ...attrs, authorId: user.id }))
.count(3)
.createMany(this.db)
}
}
}
  • Quarry CLI for the full command framework reference.
  • Testing Seeders for seeders used inside tests with TestingModule.
  • Factories for generating test data with Faker.js.
  • Database for configuring the database connection.