xiaohongshu
xiaohongshu
bknd-modify-schema
Use when modifying existing Bknd schema. Covers renaming entities, renaming fields, changing field types, altering field constraints, handling destructive changes, data migration strategies, and the sync workflow.
Full skill instructions
Modify existing schema in Bknd: rename entities/fields, change field types, or alter constraints.
bknd-create-entity)bknd.config.tsBknd's schema sync detects differences between your code and database. Some changes are safe; others cause data loss.
.required())Warning: Bknd has no native rename. Renaming = DROP old + CREATE new = DATA LOSS.
// Step 1: Add new entity alongside old
const schema = em({
// OLD - will be removed later
posts: entity("posts", {
title: text().required(),
content: text(),
}),
// NEW - desired name
articles: entity("articles", {
title: text().required(),
content: text(),
}),
});
// Step 2: Migrate data (run once via script or CLI)
const api = app.getApi();
const oldData = await api.data.readMany("posts", { limit: 10000 });
for (const item of oldData.data) {
await api.data.createOne("articles", {
title: item.title,
content: item.content,
});
}
// Step 3: Remove old entity from schema
const schema = em({
articles: entity("articles", {
title: text().required(),
content: text(),
}),
});
# Step 4: Sync with force to drop old table
npx bknd sync --force
http://localhost:1337)Warning: Bknd treats field renames as drop + create = DATA LOSS on that column.
// Step 1: Add new field alongside old
const schema = em({
users: entity("users", {
name: text(), // OLD - will be removed
full_name: text(), // NEW - desired name
}),
});
// Step 2: Migrate data
const api = app.getApi();
const users = await api.data.readMany("users", { limit: 10000 });
for (const user of users.data) {
if (user.name && !user.full_name) {
await api.data.updateOne("users", user.id, {
full_name: user.name,
});
}
}
// Step 3: Remove old field
const schema = em({
users: entity("users", {
full_name: text(),
}),
});
# Step 4: Sync with force to drop old column
npx bknd sync --force
Type changes are risky. Some conversions work; others fail or truncate.
| From | To | Notes |
|---|---|---|
text | text (with different constraints) | Usually safe |
number | text | Safe (numbers become strings) |
boolean | number | Safe (0/1 values) |
boolean | text | Safe ("true"/"false") |
| From | To | Risk |
|---|---|---|
text | number | Fails if non-numeric data |
text | boolean | Fails if not "true"/"false"/0/1 |
text | date | Fails if not valid date format |
json | text | May truncate; loses structure |
// Step 1: Add new field with new type
const schema = em({
products: entity("products", {
price: text(), // OLD - string prices
price_cents: number(), // NEW - integer cents
}),
});
// Step 2: Transform and migrate data
const api = app.getApi();
const products = await api.data.readMany("products", { limit: 10000 });
for (const product of products.data) {
if (product.price && !product.price_cents) {
const cents = Math.round(parseFloat(product.price) * 100);
await api.data.updateOne("products", product.id, {
price_cents: cents,
});
}
}
// Step 3: Remove old field, rename new if desired
const schema = em({
products: entity("products", {
price_cents: number(),
}),
});
Risk: Fails if existing records have null values.
// Before
entity("users", {
email: text(), // Optional
});
// After
entity("users", {
email: text().required(), // Now required
});
Safe approach:
.required()// Step 1: Fill nulls with default
const api = app.getApi();
const usersWithNull = await api.data.readMany("users", {
where: { email: { $isnull: true } },
});
for (const user of usersWithNull.data) {
await api.data.updateOne("users", user.id, {
email: "[email protected]",
});
}
// Step 2: Now safely add .required()
Risk: Fails if duplicates exist.
// Before
entity("users", {
username: text(),
});
// After
entity("users", {
username: text().unique(),
});
Safe approach:
.unique()// Check for duplicates via raw SQL or manual inspection
// Resolve duplicates by updating or deleting
// Then add .unique() constraint
Generally safe:
// Before
entity("users", {
email: text().required().unique(),
});
// After - loosening constraints is safe
entity("users", {
email: text(), // Now optional, non-unique
});
# See what sync would do without applying
npx bknd sync
Output shows:
# Applies only additive changes
npx bknd sync
# WARNING: This will drop tables/columns
npx bknd sync --force
# Specifically enables drop operations
npx bknd sync --drop
Error: Cannot convert column type from X to Y
Fix: Use migration approach - create new field, copy data, drop old.
Error: Column contains null values, cannot add NOT NULL
Fix: Update all null values to non-null first, then re-sync.
Error: Duplicate values exist for column
Fix: Remove duplicates before adding unique constraint.
Problem: Renamed entity/field and lost all data.
Fix: Unfortunately, data is gone. Restore from backup. Use migration approach next time.
Problem: --force doesn't seem to apply changes.
Fix: Check sync output for actual errors. May be validation issue, not permission.
For complex migrations, create a standalone script:
// scripts/migrate-schema.ts
import { App } from "bknd";
async function migrate() {
const app = new App({
connection: { url: process.env.DB_URL! },
});
await app.build();
const api = app.getApi();
console.log("Starting migration...");
// Read all records from old structure
const records = await api.data.readMany("old_entity", { limit: 100000 });
console.log(`Found ${records.data.length} records`);
// Transform and insert into new structure
let migrated = 0;
for (const record of records.data) {
await api.data.createOne("new_entity", {
// Transform fields as needed
new_field: record.old_field,
});
migrated++;
if (migrated % 100 === 0) {
console.log(`Migrated ${migrated}/${records.data.length}`);
}
}
console.log("Migration complete!");
process.exit(0);
}
migrate().catch(console.error);
Run with:
npx bun scripts/migrate-schema.ts
# or
npx ts-node scripts/migrate-schema.ts
# 1. Check sync status
npx bknd sync
# 2. Verify schema in debug output
npx bknd schema --pretty
const api = app.getApi();
// Verify field exists by querying
const result = await api.data.readMany("entity_name", { limit: 1 });
console.log(result.data[0]); // Check field names/values
DO:
npx bknd sync before forcingDON'T:
--force without previewing first.required() to fields with null data.unique() to fields with duplicatesxiaohongshu
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