@kubb/plugin-zod
Generate Zod validation schemas from your OpenAPI schema.
TIP
Support for Zod v4 when using Kubb v3.8.1, see Zod 4 migration guide
Installation
bun add -d @kubb/plugin-zodpnpm add -D @kubb/plugin-zodnpm install --save-dev @kubb/plugin-zodyarn add -D @kubb/plugin-zodOptions
output
Specify the export location for the files and define the behavior of the output.
output.path
Path to the output folder or file that contains the generated code.
TIP
if output.path is a file, group cannot be used.
| Type: | string |
|---|---|
| Required: | true |
| Default: | 'zod' |
output.barrelType
Specify what to export and optionally disable barrel file generation.
TIP
Using propagate will prevent a plugin from creating a barrel file, but it will still propagate, allowing output.barrelType to export the specific function or type.
| Type: | 'all' | 'named' | 'propagate' | false |
|---|---|
| Required: | false |
| Default: | 'named' |
export * from "./gen/petService.ts"export { PetService } from "./gen/petService.ts"output.banner
Add a banner comment at the top of every generated file.
| Type: | string | (oas: Oas) => string |
|---|---|
| Required: | false |
output.footer
Add a footer comment at the end of every generated file.
| Type: | string | (oas: Oas) => string |
|---|---|
| Required: | false |
output.override
Whether Kubb overrides existing external files that can be generated if they already exist.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
contentType
Define which content type to use.
By default, Kubb uses the first JSON-valid media type.
| Type: | 'application/json' | (string & {}) |
|---|---|
| Required: | false |
group
Grouping combines files in a folder based on a specific type.
For example, with this configuration:
group: {
type: 'tag',
name({ group }){
return `${group}Controller`
}
}This generates the following structure:
.
├── src/
│ └── petController/
│ │ ├── addPet.ts
│ │ └── getPet.ts
│ └── storeController/
│ ├── createStore.ts
│ └── getStoreById.ts
├── petStore.yaml
├── kubb.config.ts
└── package.jsongroup.type
Specify the property to group files by. Required when group is defined.
| Type: | 'tag' |
|---|---|
| Required: | true* |
NOTE
Required: true* means this is required only when the group option is used. The group option itself is optional.
'tag': Uses the first tag fromoperation.getTags().at(0)?.name
group.name
Return the name of a group based on the group name, this will be used for the file and name generation.
| Type: | (context: GroupContext) => string |
|---|---|
| Required: | false |
| Default: | (ctx) => '${ctx.group}Controller' |
importPath
| Type: | string |
|---|---|
| Required: | false |
| Default: | 'zod' |
typed
Use TypeScript(@kubb/plugin-ts) to add type annotation.
IMPORTANT
We rely on ToZod from the creator of Zod to create a schema based on a type. Kubb contains its own version to those kind of conversions.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
inferred
Return Zod generated schema as type with z.infer.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
dateType
Choose to use date or datetime as JavaScript Date instead of string.
See DateTimes.
| Type: | false | 'string' | 'stringOffset' | 'stringLocal' | 'date' |
|---|---|
| Required: | false |
| Default: | 'string' |
z.string();z.string().datetime();z.string().datetime({ offset: true });z.string().datetime({ local: true });z.date();unknownType
Which type to use when the Swagger/OpenAPI file is not providing more information.
| Type: | 'any' | 'unknown' | 'void' |
|---|---|
| Required: | false |
| Default: | 'any' |
z.any();z.unknown();z.void()emptySchemaType
Which type to use for empty schema values.
| Type: | 'any' | 'unknown' | 'void' |
|---|---|
| Required: | false |
| Default: | unknownType |
z.any()z.unknown()z.void()coercion
Use of z.coerce.string() instead of z.string(). Coercion for primitives
| Type: | boolean | { dates?: boolean, strings?: boolean, numbers?: boolean} |
|---|---|
| Required: | false |
| Default: | false' |
z.coerce.string();
z.coerce.date();
z.coerce.number();z.string();
z.date();
z.number();z.string();
z.date();
z.coerce.number();operations
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
mapper
| Type: | Record<string, string> |
|---|---|
| Required: | false |
version
Which version of Zod should be used.
| Type: | '3' | '4' |
|---|---|
| Required: | false |
| Default: | '3' |
guidType
Which validator to use for OpenAPI format: uuid.
| Type: | 'uuid' | 'guid' |
|---|---|
| Required: | false |
| Default: | 'uuid' |
NOTE
guid is only used with version: '4'. With version: '3', Kubb falls back to uuid.
z.uuid()z.guid()mini beta new in 4.8.0
Use Zod Mini's functional API for better tree-shaking support.
When enabled, generates functional syntax (e.g., z.optional(z.string())) instead of chainable methods (e.g., z.string().optional()).
Requires Zod v4 or later. When mini: true, version will be set to '4' and importPath will default to 'zod/mini'.
WARNING
This feature is currently in beta. The API may change in future releases.
TIP
Zod Mini provides a smaller bundle size with better tree-shaking. See Zod Mini documentation for more details.
| Type: | boolean |
|---|---|
| Required: | false |
| Default: | false |
// Import from zod/mini
import { z } from 'zod/mini'
// Functional syntax for better tree-shaking
z.optional(z.string())
z.nullable(z.number())
z.array(z.string()).check(z.minLength(1), z.maxLength(10))// Import from zod or zod/v4
import { z } from 'zod'
// Chainable method syntax
z.string().optional()
z.number().nullable()
z.array(z.string()).min(1).max(10)include
Array containing include parameters to include tags, operations, methods, paths, or content types.
| Type: | Array<Include> |
|---|---|
| Required: | false |
export type Include = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
pattern: string | RegExp
}exclude
Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
| Type: | Array<Exclude> |
|---|---|
| Required: | false |
export type Exclude = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
pattern: string | RegExp
}override
Array containing override parameters to override options based on tags, operations, methods, paths, or content types.
| Type: | Array<Override> |
|---|---|
| Required: | false |
export type Override = {
type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
pattern: string | RegExp
options: PluginOptions
}generators
See Generators for more information on how to use generators.
| Type: | Array<Generator<PluginZod>> |
|---|---|
| Required: | false |
transformers
transformers.name
Customize the names based on the type that is provided by the plugin.
| Type: | (name: string, type?: ResolveType) => string |
|---|---|
| Required: | false |
type ResolveType = "file" | "function" | "type" | "const";transformers.schema
Customize the schema based on the type that is provided by the plugin.
| Type: | (props: { schema?: SchemaObject; name?: string; parentName?: string}, defaultSchemas: Schema[],) => Schema[] | undefined |
|---|---|
| Required: | false |
wrapOutput
Modify the generated zod schema.
TIP
This is useful for cases where you need to extend the generated zod output with additional properties from an OpenAPI schema. E.g. in the case of OpenAPI -> Zod -> OpenAPI, you could include the examples from the schema for a given property and then ultimately provide a modified schema to a router that supports zod and OpenAPI spec generation.
wrapOutput: ({ output, schema }) => {
const metadata: ZodOpenAPIMetadata = {};
if (schema.example) {
metadata.example = schema.example;
}
if (Object.keys(metadata).length > 0) {
return `${output}.openapi(${JSON.stringify(metadata)})`;
}
};| Type: | (arg: { output: string; schema: SchemaObject }) => string | undefined |
|---|---|
| Required: | false |
Example
import { defineConfig } from "@kubb/core";
import { pluginOas } from "@kubb/plugin-oas";
import { pluginTs } from "@kubb/plugin-ts";
import { pluginZod } from "@kubb/plugin-zod";
export default defineConfig({
input: {
path: "./petStore.yaml",
},
output: {
path: "./src/gen",
},
plugins: [
pluginOas(),
pluginTs(),
pluginZod({
output: {
path: "./zod",
},
group: { type: "tag", name: ({ group }) => `${group}Schemas` },
typed: true,
dateType: "stringOffset",
unknownType: "unknown",
importPath: "zod",
wrapOutput: ({ output, schema }) =>
`${output}.openapi({ description: 'This is a custom extension' })`,
}),
],
});