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 --zod

This adds a fourth file to the output directory alongside types.ts, metadata.ts, and index.ts:

  • zod.tsXSchema, XCreateSchema, and XUpdateSchema for 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 zod

The 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

ColumnZod
text, varchar, uuidz.string()
int, float, numericz.number()
booleanz.boolean()
timestamp, datez.coerce.date()
json, jsonbz.unknown()
enum columnz.enum([...labels])
array columnelement schema .array()
vectorz.array(z.number())
nullable columnschema .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