xiaohongshu
xiaohongshu
bknd-seed-data
Use when populating a Bknd database with initial or test data. Covers the seed function in options, ctx.em.mutator() for insertOne/insertMany, conditional seeding, environment-based data, and common patterns for dev/test fixtures.
Full skill instructions
Populate your Bknd database with initial, test, or development data using the built-in seed function.
Note: Seed function is code-only—no UI equivalent. For one-off data entry, use the admin panel Data section directly.
The seed function lives in the options section of your config:
import { type BunBkndConfig, serve } from "bknd/adapter/bun";
import { em, entity, text, boolean } from "bknd";
const schema = em({
todos: entity("todos", {
title: text().required(),
done: boolean({ default_value: false }),
}),
});
const config: BunBkndConfig = {
connection: { url: "file:data.db" },
config: {
data: schema.toJSON(),
},
options: {
seed: async (ctx) => {
// Seed logic here
},
},
};
serve(config);
Use ctx.em.mutator(entity) for server-side inserts:
options: {
seed: async (ctx) => {
// Insert single record
await ctx.em.mutator("todos").insertOne({
title: "Welcome task",
done: false,
});
// Insert multiple records
await ctx.em.mutator("todos").insertMany([
{ title: "Learn Bknd basics", done: false },
{ title: "Create first entity", done: true },
{ title: "Set up authentication", done: false },
]);
},
}
Insert parent records first, then children:
options: {
seed: async (ctx) => {
// Create users first
const users = await ctx.em.mutator("users").insertMany([
{ email: "[email protected]", name: "Admin" },
{ email: "[email protected]", name: "User" },
]);
// Create posts referencing users
await ctx.em.mutator("posts").insertMany([
{ title: "First Post", author_id: users[0].id },
{ title: "Second Post", author_id: users[1].id },
]);
},
}
Check if data exists before seeding to avoid duplicates:
options: {
seed: async (ctx) => {
// Check if already seeded
const existing = await ctx.em.repo("users").findOne({
where: { email: { $eq: "[email protected]" } },
});
if (existing) {
console.log("Database already seeded");
return;
}
// Seed data
await ctx.em.mutator("users").insertOne({
email: "[email protected]",
name: "Admin",
});
},
}
import { type BunBkndConfig, serve } from "bknd/adapter/bun";
import { em, entity, text, boolean, number, date } from "bknd";
const schema = em({
users: entity("users", {
email: text().required().unique(),
name: text(),
role: text({ default_value: "user" }),
}),
posts: entity("posts", {
title: text().required(),
content: text(),
published: boolean({ default_value: false }),
view_count: number({ default_value: 0 }),
created_at: date({ default_value: "now" }),
}),
tags: entity("tags", {
name: text().required().unique(),
}),
});
type Database = (typeof schema)["DB"];
declare module "bknd" {
interface DB extends Database {}
}
const config: BunBkndConfig = {
connection: { url: "file:data.db" },
config: {
data: schema.toJSON(),
},
options: {
seed: async (ctx) => {
// Check if already seeded
const count = await ctx.em.repo("users").count();
if (count > 0) {
console.log("Skipping seed: data exists");
return;
}
console.log("Seeding database...");
// Seed users
const [admin, author] = await ctx.em.mutator("users").insertMany([
{ email: "[email protected]", name: "Admin", role: "admin" },
{ email: "[email protected]", name: "Author", role: "author" },
]);
// Seed tags
const tags = await ctx.em.mutator("tags").insertMany([
{ name: "javascript" },
{ name: "typescript" },
{ name: "bknd" },
]);
// Seed posts
await ctx.em.mutator("posts").insertMany([
{
title: "Getting Started with Bknd",
content: "Learn the basics...",
published: true,
author_id: author.id,
},
{
title: "Advanced Patterns",
content: "Deep dive into...",
published: false,
author_id: admin.id,
},
]);
console.log("Seed complete!");
},
},
};
serve(config);
For browser-based apps using BkndBrowserApp:
import { BkndBrowserApp } from "bknd/adapter/browser";
function App() {
return (
<BkndBrowserApp
config={{
data: schema.toJSON(),
}}
options={{
seed: async (ctx) => {
await ctx.em.mutator("todos").insertMany([
{ title: "Sample task 1", done: false },
{ title: "Sample task 2", done: true },
]);
},
}}
>
<YourApp />
</BkndBrowserApp>
);
}
Different data for dev vs production:
options: {
seed: async (ctx) => {
const isDev = process.env.NODE_ENV !== "production";
// Always seed admin
await ctx.em.mutator("users").insertOne({
email: "[email protected]",
name: "Admin",
role: "admin",
});
// Dev-only test data
if (isDev) {
await ctx.em.mutator("users").insertMany([
{ email: "[email protected]", name: "Test User 1" },
{ email: "[email protected]", name: "Test User 2" },
]);
// Generate bulk test data
const testPosts = Array.from({ length: 50 }, (_, i) => ({
title: `Test Post ${i + 1}`,
content: `Content for test post ${i + 1}`,
published: i % 2 === 0,
}));
await ctx.em.mutator("posts").insertMany(testPosts);
}
},
}
| Scenario | Seed Runs? |
|---|---|
| First startup (empty DB) | Yes |
| Subsequent startups | Yes (every time) |
| After schema sync | Yes |
| Production deployment | Yes (use guards!) |
Important: The seed function runs on every startup. Always add existence checks to prevent duplicate data.
| Method | Description | Example |
|---|---|---|
insertOne(data) | Insert single record | mutator("users").insertOne({ email: "..." }) |
insertMany(data[]) | Insert multiple records | mutator("users").insertMany([...]) |
async function seedIfNotExists(ctx, entity: string, where: object, data: object) {
const existing = await ctx.em.repo(entity).findOne({ where });
if (!existing) {
return ctx.em.mutator(entity).insertOne(data);
}
return existing;
}
// Usage
options: {
seed: async (ctx) => {
await seedIfNotExists(ctx, "users",
{ email: { $eq: "[email protected]" } },
{ email: "[email protected]", name: "Admin", role: "admin" }
);
},
}
function createTestUser(overrides = {}) {
return {
email: `user${Date.now()}@test.com`,
name: "Test User",
role: "user",
...overrides,
};
}
function createTestPost(authorId: number, overrides = {}) {
return {
title: "Test Post",
content: "Lorem ipsum...",
published: false,
author_id: authorId,
...overrides,
};
}
// Usage
options: {
seed: async (ctx) => {
const user = await ctx.em.mutator("users").insertOne(
createTestUser({ role: "admin" })
);
await ctx.em.mutator("posts").insertMany([
createTestPost(user.id, { title: "Post 1", published: true }),
createTestPost(user.id, { title: "Post 2" }),
]);
},
}
import { faker } from "@faker-js/faker";
options: {
seed: async (ctx) => {
const users = Array.from({ length: 10 }, () => ({
email: faker.internet.email(),
name: faker.person.fullName(),
role: faker.helpers.arrayElement(["user", "author", "admin"]),
}));
await ctx.em.mutator("users").insertMany(users);
},
}
Problem: Seed runs every startup, creating duplicates.
Fix: Check for existing data:
seed: async (ctx) => {
const count = await ctx.em.repo("users").count();
if (count > 0) return; // Already seeded
// Seed logic...
}
Problem: Foreign key constraint failed error.
Fix: Insert parent records before children:
// ❌ Wrong order
await ctx.em.mutator("posts").insertOne({ author_id: 1, ... }); // User doesn't exist!
await ctx.em.mutator("users").insertOne({ id: 1, ... });
// ✅ Correct order
const user = await ctx.em.mutator("users").insertOne({ ... });
await ctx.em.mutator("posts").insertOne({ author_id: user.id, ... });
Problem: NOT NULL constraint failed error.
Fix: Include all required fields:
// ❌ Missing required field
await ctx.em.mutator("users").insertOne({ name: "Admin" });
// Error: email is required
// ✅ Include all required fields
await ctx.em.mutator("users").insertOne({
email: "[email protected]", // required
name: "Admin"
});
Problem: Test data appears in production.
Fix: Guard with environment check:
seed: async (ctx) => {
if (process.env.NODE_ENV === "production") {
// Only seed essential data in production
const adminExists = await ctx.em.repo("users").findOne({
where: { role: { $eq: "admin" } },
});
if (!adminExists) {
await ctx.em.mutator("users").insertOne({
email: process.env.ADMIN_EMAIL,
name: "Admin",
role: "admin",
});
}
return;
}
// Full dev seed...
}
After seeding, verify data was inserted:
seed: async (ctx) => {
// ... insert data ...
// Verify
const userCount = await ctx.em.repo("users").count();
const postCount = await ctx.em.repo("posts").count();
console.log(`Seeded: ${userCount} users, ${postCount} posts`);
}
Or via API after startup:
const api = app.getApi();
const { data } = await api.data.readMany("users");
console.log("Users:", data.length);
DO:
DON'T:
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience