Seed
A seed script populates sample records when a developer runs pnpm run db:seed from tinycld/. The seeder creates the test user and a collaborator, then calls each present package’s seed function in turn. If your package has useful dev data (example contacts, a starter mailbox, a demo calendar), ship a seed.
Declaring a seed
Point seed.script at a subpath (no extension) inside the package:
seed: { script: 'seed' },
And expose the module in package.json:
{
"exports": {
"./seed": "./tinycld/example/seed.ts"
}
}
The seed function
Default-export an async function that takes a PocketBase client and a context object:
import type PocketBase from 'pocketbase'
interface SeedUser {
id: string
username: string
email: string
name: string
}
interface SeedContext {
user: SeedUser
companion?: SeedUser
}
export default async function seed(pb: PocketBase, { user, companion }: SeedContext) {
await pb.collection('example_items').create({
title: 'Sample item',
owner: user.id,
})
if (companion) {
await pb.collection('example_items').create({
title: 'A teammate\'s item',
owner: companion.id,
})
}
}
pb is already authenticated as the superuser, so you can write to any collection. Declare the context type locally as the structural subset you use (the canonical one is SeedContext in @tinycld/core/lib/packages/config-types). It carries:
user- the test account (user@tinycld.org). Useuser.idfor every owner, author, and user foreign key; there is no org relation to set.usernameis what Mail derives mailbox addresses from, so seed from it rather than the email’s local part.companion- a second seeded account (collaborator@tinycld.org, rolemember) for fixtures that need another person: a teammate-owned board, a shared calendar, a share recipient. Resolve “the other person” to this user rather than queryingusersforid != user.id. It is optional — a deployment seeded without one still works, so guard on it.
The seeder runs your seed once per invocation. The database is wiped before seeding, so you don’t need idempotency guards - write records straight through.
Keep seeds small
A seed exists so a developer can open the UI and see something. A handful of rows per collection is plenty - enough to exercise list views, navigation, and empty-state transitions. Avoid pulling in large fixture files or generating thousands of records; that’s what Playwright factory helpers are for.
If you need multiple related records, create parents first and feed their IDs into children. Wrap unrelated groups in functions so the seed file stays readable:
export default async function seed(pb: PocketBase, ctx: SeedContext) {
await seedLabels(pb, ctx)
await seedExampleItems(pb, ctx)
}
The generator emits tinycld/tinycld.seeds.ts, a Node-only list mapping each present package’s slug (and its dependencies) to its default-exported seed function. tinycld/scripts/seed-db.ts imports that list and iterates it, in dependency order, after creating the test user and collaborator. You don’t interact with the generated file directly.