Seeders
Populate your database with initial data using typed seeder files.
Overview
Seeders are TypeScript files in database/seeders/ that insert initial or test data. Each seeder exports an async run() function. Seeders use the same model and service APIs as the rest of your application.
database/
└── seeders/
├── 01_user_seeder.ts
└── 02_post_seeder.tsmake:seeder
Generate a new seeder:
tekir make:seeder userCreated: database/seeders/user_seeder.tsSeeder File Format
Export an async run function. Use models, services, or raw SQL, whatever you need.
import { User } from '~/models/user'
import { hash } from '#services'
export async function run() {
const pw = await hash.make('secret')
await User.createMany([
{ name: 'Alice', email: '[email protected]', role: 'admin', password: pw },
{ name: 'Bob', email: '[email protected]', role: 'user', password: pw },
{ name: 'Charlie', email: '[email protected]', role: 'user', password: pw }
])
}import { Post } from '~/models/post'
export async function run() {
await Post.createMany([
{ title: 'Getting Started with tekir', body: 'tekir is a Bun-native framework...', userId: 1, status: 'published' },
{ title: 'Building APIs', body: 'Learn how to build REST APIs...', userId: 1, status: 'published' },
{ title: 'Draft Post', body: 'This is still a draft...', userId: 2, status: 'draft' }
])
}You can also use raw SQL for simple inserts:
import { db } from '#services'
export async function run() {
await db.exec(`
INSERT INTO settings (key, value) VALUES
('site_name', 'My App'),
('theme', 'dark'),
('locale', 'en')
`)
}Running Seeders
Run all seeders in alphabetical order:
# Run all seeders in alphabetical order
tekir seedSeeded: 01_user_seeder.ts
Seeded: 02_post_seeder.tsIdempotent Seeders
Running seed multiple times inserts duplicate records by default. Guard against this by checking if data exists first:
import { User } from '~/models/user'
import { hash } from '#services'
export async function run() {
// Skip if users already exist
if ((await User.count()) > 0) return
const pw = await hash.make('secret')
await User.createMany([
{ name: 'Alice', email: '[email protected]', role: 'admin', password: pw },
{ name: 'Bob', email: '[email protected]', role: 'user', password: pw }
])
}Or use firstOrCreate() for per-row idempotency:
import { User } from '~/models/user'
import { hash } from '#services'
export async function run() {
const pw = await hash.make('secret')
await User.firstOrCreate(
{ email: '[email protected]' },
{ name: 'Alice', role: 'admin', password: pw }
)
await User.firstOrCreate(
{ email: '[email protected]' },
{ name: 'Bob', role: 'user', password: pw }
)
}Seeder Order
Seeders run in alphabetical order. Prefix filenames with numbers to control execution order and satisfy foreign key dependencies:
database/seeders/
01_user_seeder.ts , runs first
02_category_seeder.ts , runs second
03_post_seeder.ts , runs third (depends on users + categories)Fresh + Seed
To wipe and re-seed your local database during development:
# Drop all tables, re-run migrations, then seed
tekir migrate:fresh
tekir seedmigrate:fresh: drops all tables and re-runs all migrationsseed: populates with seed data