- 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
bun add -d @kubb/plugin-zodpnpm add -D @kubb/plugin-zodnpm install --save-dev @kubb/plugin-zodyarn add -D @kubb/plugin-zodDependencies
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 / Format | Standard Zod Output | Zod Mini Output | Notes |
|---|---|---|---|
integer | z.int() | z.int() | Coerces to z.coerce.number().int() when coercion.numbers is enabled |
integer, format: int32 | z.int32() | z.int32() | 32-bit signed integer |
integer, format: uint32 | z.uint32() | z.uint32() | 32-bit unsigned integer |
integer, format: int64 | z.bigint() | z.bigint() | 64-bit integer |
string, format: byte / base64 | z.base64() | z.base64() | Base64 string validation |
string, format: base64url | z.base64url() | z.base64url() | URL-safe base64 string validation |
string, format: jwt | z.jwt() | z.jwt() | JSON Web Token format |
string, format: ulid | z.ulid() | z.ulid() | ULID format |
string, format: iban | z.iban() | z.iban() | International Bank Account Number |
string, format: duration | z.iso.duration() | z.iso.duration() | ISO 8601 duration format |
string, format: uuid | z.uuid() (or z.guid()) | z.uuid() (or z.guid()) | Configured via guidType |
string, format: email | z.email() | z.email() | Email format |
string, format: uri / url | z.url() | z.url() | URL format |
string, format: ipv4 / ipv6 | z.ipv4() / z.ipv6() | z.ipv4() / z.ipv6() | IP address format |
string, format: date | z.iso.date() | z.iso.date() | ISO 8601 date |
string, format: date-time | z.iso.datetime() | z.string() | ISO 8601 date-time |
string, format: time | z.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: true | z.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
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 anadditionalPropertiesschema generatesz.record(z.string(), valueSchema). - Open objects (
additionalProperties: true): Objects that permit arbitrary undeclared properties generate nativez.looseObject(shape)(the counterpart toz.strictObject(...)). - Key validation (
propertyNames): In OpenAPI 3.1, schemas declaringpropertyNamesvalidate 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)orz.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). Emittingz.partialRecordmatches OpenAPI partial semantics (only validating present keys) and infersPartial<Record<Keys, Value>>.
- Open key schemas (such as regex patterns, formats like UUID, or length constraints) pass the validated key schema as the first argument, e.g.
- Pattern properties (
patternProperties): Key regex patterns are combined into an alternation and emitted asz.record(z.string().regex(...), valueSchema)(orz.string().check(z.regex(...))when usingmini: true). - Mixed objects: Objects declaring fixed properties alongside typed
additionalPropertiescontinue to use.catchall(valueSchema)to preserve their declared shape.