Zod Schemas
turbine generate --zod emits a zod.ts file next to your generated types, with a Zod schema per table. Use it to validate request bodies, form input, or any untrusted data against the same shape your database expects, derived from column metadata, so it can't drift from your schema.
npx turbine generate --zodThis adds a fourth file to the output directory alongside types.ts, metadata.ts, and index.ts:
zod.ts,XSchema,XCreateSchema, andXUpdateSchemafor each table.
Zod is a user-side dependency. The generated file imports zod, but the Turbine runtime never does, install zod yourself to use the output.
npm install zodThe three schemas#
For a posts table, generation emits:
import { z } from 'zod';
// Full entity, every column
export const PostSchema = z.object({
id: z.number(),
title: z.string(),
views: z.number(),
published: z.boolean(),
createdAt: z.coerce.date(),
});
// Create input, PK, defaulted, and nullable columns optional
export const PostCreateSchema = z.object({
id: z.number().optional(),
title: z.string(),
views: z.number().optional(),
published: z.boolean(),
createdAt: z.coerce.date().optional(),
});
// Update input, every non-PK column optional, PK omitted
export const PostUpdateSchema = z.object({
title: z.string().optional(),
views: z.number().optional(),
published: z.boolean().optional(),
createdAt: z.coerce.date().optional(),
});XCreateSchema and XUpdateSchema mirror the generated *Create / *Update input types: the create schema makes primary-key, defaulted, and nullable columns optional; the update schema makes every non-PK column optional and drops the primary key.
Type mapping#
| Column | Zod |
|---|---|
text, varchar, uuid | z.string() |
int, float, numeric | z.number() |
boolean | z.boolean() |
timestamp, date | z.coerce.date() |
json, jsonb | z.unknown() |
| enum column | z.enum([...labels]) |
| array column | element schema .array() |
vector | z.array(z.number()) |
| nullable column | schema .nullable() |
z.coerce.date() accepts both Date objects and date strings, so it validates JSON request bodies where dates arrive as strings.
STORED generated columns are omitted from XCreateSchema and XUpdateSchema. You can't write them (see Views & Generated Columns), but they remain in the full XSchema.
Using the schemas#
import { PostCreateSchema } from './generated/turbine/zod';
// Validate an untrusted request body before writing
const data = PostCreateSchema.parse(await req.json());
const post = await db.posts.create({ data });See also#
- CLI, the
generatecommand and every flag. - Views & Generated Columns, why generated columns are dropped from Create/Update.
- Schema & Migrations, the column metadata these schemas derive from.