Registry and Schemas
Understand block definitions, registry inference, and create/select validation.
The registry is the center of a block feature. It keeps definitions as plain data while providing typed schemas and runtime helpers.
Block Definitions
export type BlockDefinition = {
slug: string;
label: string;
description?: string;
schema: z.ZodType;
};The schema describes only data. Storage-owned fields live outside the schema.
const storedBlock = {
id: "block_1",
slug: "hero",
index: 0,
data: {
titlePart1: "Make space",
titlePart2: "for growth",
},
};Registry Output
const registry = createBlockRegistry([heroBlock, summaryBlock]);The registry exposes:
definitions: the original definitions in ordercreateSchema: discriminated union for{ slug, data }selectSchema: discriminated union for{ id, slug, index, data }getDefinition(slug): runtime lookup for metadata/schemapatchData({ block, patch }): merge partial data and validate the result
Inferred Types
Use registry-level inference for app code.
type PageBlock = InferBlock<typeof pageBlocks>;
type PageBlockInput = InferBlockInput<typeof pageBlocks>;Use definition-level inference inside individual block files.
type HeroBlock = InferBlockFromDefinition<typeof heroBlock>;
type HeroCreateInput = InferBlockInputFromDefinition<typeof heroBlock>;Select Schema
Use selectSchema at boundaries that read persisted blocks.
const rows = await db.query.pageBlocks.findMany({ orderBy: asc(pageBlocksTable.index) });
const blocks = z.array(pageBlocks.selectSchema).parse(rows);If old stored data no longer matches a block schema, parsing fails early before UI rendering.
Create Schema
Use createSchema in create mutations.
const inputSchema = z.object({
pageId: z.string(),
block: pageBlocks.createSchema,
});The server still assigns id and index.
Patch Data
Inline editing usually sends partial field updates. patchData merges the patch
into the existing data object and validates the full result against the block schema.
const patchedData = pageBlocks.patchData({
block: existingBlock,
patch: { titlePart1: "New title" },
});
if (!patchedData.success) {
throw new Error("Unknown block type");
}
await db.update(pageBlocksTable).set({ data: patchedData.data });Unknown slugs return { success: false }. Schema validation errors still throw
from Zod so callers can use normal validation/error handling.