Open Studio
Officialv5.4.1MITkubb >=5.0.0node >=22

@kubb/plugin-zod

Generates Zod v4 schemas from your OpenAPI spec so you validate API responses, form input, and query params at runtime.

zodvalidationschemaruntime-validationcodegenopenapi
Stijn Van Hulle

Stijn Van Hulle

@stijnvanhulle

Downloads
813k/ mo
Stars
8
Bundle size
554.8 kB
Updated
today

@kubb/plugin-zod turns your OpenAPI schemas into Zod v4 schemas. Use them to validate API responses at runtime, build form schemas, or feed router libraries that take Zod (tRPC, Hono, Elysia).

Pair it with a client plugin (@kubb/plugin-axios or @kubb/plugin-fetch) and set the client's validator: 'zod' to validate every response.

Installation ​

shell
bun add -d @kubb/plugin-zod
shell
pnpm add -D @kubb/plugin-zod
shell
npm install --save-dev @kubb/plugin-zod
shell
yarn add -D @kubb/plugin-zod

Dependencies ​

Important

The generated schemas need Zod v4 or higher.

The generated schemas stand alone: they import z from your project, so add Zod to your dependencies. Set inferred: true to export a z.infer type alias next to each schema, which makes the schemas the single source of truth for types without @kubb/plugin-ts.

Format and type mappings ​

@kubb/plugin-zod generates native Zod v4 schemas for standard OpenAPI types and formats:

OpenAPI Type / FormatStandard Zod OutputZod Mini OutputNotes
integerz.int()z.int()Coerces to z.coerce.number().int() when coercion.numbers is enabled
integer, format: int32z.int32()z.int32()32-bit signed integer
integer, format: uint32z.uint32()z.uint32()32-bit unsigned integer
integer, format: int64z.bigint()z.bigint()64-bit integer
string, format: byte / base64z.base64()z.base64()Base64 string validation
string, format: base64urlz.base64url()z.base64url()URL-safe base64 string validation
string, format: jwtz.jwt()z.jwt()JSON Web Token format
string, format: ulidz.ulid()z.ulid()ULID format
string, format: ibanz.iban()z.iban()International Bank Account Number
string, format: durationz.iso.duration()z.iso.duration()ISO 8601 duration format
string, format: uuidz.uuid() (or z.guid())z.uuid() (or z.guid())Configured via guidType
string, format: emailz.email()z.email()Email format
string, format: uri / urlz.url()z.url()URL format
string, format: ipv4 / ipv6z.ipv4() / z.ipv6()z.ipv4() / z.ipv6()IP address format
string, format: datez.iso.date()z.iso.date()ISO 8601 date
string, format: date-timez.iso.datetime()z.string()ISO 8601 date-time
string, format: timez.iso.time()z.iso.time()ISO 8601 time
object, additionalProperties: <schema>z.record(z.string(), schema)z.record(z.string(), schema)Dictionary with no fixed properties
object, additionalProperties: truez.looseObject(shape)z.looseObject(shape)Open/passthrough object allowing extra keys
object, propertyNames: <schema>z.record(keySchema, schema)z.record(keySchema, schema)Dynamic map with validated key schema (e.g. pattern, format)
object, propertyNames: <enum>z.partialRecord(enumSchema, schema)z.partialRecord(enumSchema, schema)Closed key schemas use partial record to avoid exhaustiveness

Example ​

typescript
import { defineConfig } from 'kubb'
import { pluginZod } from '@kubb/plugin-zod'

export default defineConfig({
  input: './petStore.yaml',
  output: { path: './src/gen' },
  plugins: [
    pluginZod({
      output: { path: './zod', mode: 'directory' },
      group: { type: 'tag', name: ({ group }) => `${group}Schemas` },
      inferred: true,
      importPath: 'zod',
    }),
  ],
})

Dictionaries, open objects, and key schemas ​

OpenAPI schemas representing dynamic maps, open objects, or pattern-matched keys are emitted using Zod v4's native z.record(keySchema, valueSchema), z.partialRecord(...), and z.looseObject(...):

  • Dictionaries (additionalProperties: <schema>): An object with no fixed properties and an additionalProperties schema generates z.record(z.string(), valueSchema).
  • Open objects (additionalProperties: true): Objects that permit arbitrary undeclared properties generate native z.looseObject(shape) (the counterpart to z.strictObject(...)).
  • Key validation (propertyNames): In OpenAPI 3.1, schemas declaring propertyNames validate dictionary key names:
    • Open key schemas (such as regex patterns, formats like UUID, or length constraints) pass the validated key schema as the first argument, e.g. z.record(z.string().regex(/^[a-z]+$/), valueSchema) or z.record(z.uuid(), valueSchema).
    • Closed key schemas (such as enums, single-value literals, or unions of enums) emit z.partialRecord(enumSchema, valueSchema). In Zod v4, z.record(enum, ...) enforces exhaustiveness (requiring all enum keys to be present in the input). Emitting z.partialRecord matches OpenAPI partial semantics (only validating present keys) and infers Partial<Record<Keys, Value>>.
  • Pattern properties (patternProperties): Key regex patterns are combined into an alternation and emitted as z.record(z.string().regex(...), valueSchema) (or z.string().check(z.regex(...)) when using mini: true).
  • Mixed objects: Objects declaring fixed properties alongside typed additionalProperties continue to use .catchall(valueSchema) to preserve their declared shape.

See also ​