Skip to content

Generate Zod schemas from PocketBase collection definitions.

The @karnak19/pbkit-zod package provides a plugin that generates Zod schemas from your PocketBase collections, preserving field constraints as validations.

Terminal window
bun add @karnak19/pbkit-zod zod

Add the plugin to your pbkit.config.ts:

import { zodPlugin } from "@karnak19/pbkit-zod"
export default {
input: "https://my-pb.example.com",
output: "./src/generated",
sdk: {
baseUrl: "https://my-pb.example.com",
},
plugins: [zodPlugin],
}

After running bunx pbkit generate, a zod.gen.ts file is created alongside types.gen.ts and sdk.gen.ts.

The plugin generates three schemas per collection:

Extends BaseRecordSchema (or AuthRecordSchema for auth collections) with typed fields:

import { ArticlesRecordSchema } from "./generated/zod.gen"
const result = ArticlesRecordSchema.safeParse(response)
if (result.success) {
console.log(result.data.title) // fully typed
}

For validating create payloads. Excludes autodate and primary key fields:

import { ArticlesCreateSchema } from "./generated/zod.gen"
const result = ArticlesCreateSchema.safeParse({
title: "Hello",
status: "draft",
author: "USER_ID",
})

A partial version of the create schema:

import { ArticlesUpdateSchema } from "./generated/zod.gen"
const result = ArticlesUpdateSchema.safeParse({
title: "Updated title",
})

PocketBase field constraints are translated to Zod validations:

PocketBase constraintZod validation
text.minz.string().min(n)
text.maxz.string().max(n)
text.patternz.string().regex(/pattern/)
email typez.string().email()
url typez.string().url()
number.min / number.maxz.number().min(n) / z.number().max(n)
number.noDecimalz.number().int()
select with valuesz.enum(["a", "b", "c"])
select multiplez.array(z.enum([...])).max(n)
date typez.string().datetime({ offset: true })
password.minz.string().min(n)
field not required.optional()
import { ArticlesCreateSchema } from "./generated/zod.gen"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
function CreateArticle() {
const { register, handleSubmit } = useForm({
resolver: zodResolver(ArticlesCreateSchema),
})
const onSubmit = (data) => {
createArticle(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("title")} />
<select {...register("status")}>
<option value="draft">Draft</option>
<option value="published">Published</option>
</select>
</form>
)
}

Use both plugins together for full type safety and runtime validation:

import { zodPlugin } from "@karnak19/pbkit-zod"
import { tanstackPlugin } from "@karnak19/pbkit-tanstack"
export default {
input: "https://my-pb.example.com",
output: "./src/generated",
plugins: [zodPlugin, tanstackPlugin],
}

The plugin respects the collections config — excluded collections won’t generate schemas:

export default {
collections: {
_superusers: { exclude: true },
},
plugins: [zodPlugin],
}