@skmtc/gen-zod
OpenAPI to Zod schema generator for Skmtc.
Supported Features
Getting started
Install Skmtc
deno install -g -A --unstable-worker-options jsr:@skmtc/cli -n skmtc -f
Skmtc runs on Deno. You can install it using
Create project and generate artifacts using TUI
skmtc

Create project and generate artifacts using CLI
# Create project
skmtc init <project name>
# Install Zod generator
skmtc install @skmtc/gen-zod <project name>
# Bundle generator code
skmtc bundle <project name>
# Generate artifacts from OpenAPI schema
skmtc generate <project name> <path or url to openapi schema>
Usage Examples
Basic Primitive Types
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"id": { "type": "string" },
"age": { "type": "number" },
"score": { "type": "integer" },
"isActive": { "type": "boolean" }
},
"required": ["id", "age", "score", "isActive"]
}
}
}
}
|
import { z } from "zod";
export const user = z.object({
id: z.string(),
age: z.number(),
score: z.number().int(),
isActive: z.boolean(),
});
|
Optional Properties
Properties not in the required array become optional:
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Profile": {
"type": "object",
"properties": {
"username": { "type": "string" },
"bio": { "type": "string" },
"website": { "type": "string" }
},
"required": ["username"]
}
}
|
export const profile = z.object({
username: z.string(),
bio: z.string().optional(),
website: z.string().optional(),
});
|
Enums and Literals
Single enum values become literals, multiple values become z.enum:
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Status": {
"type": "string",
"enum": ["active", "inactive", "pending"]
},
"Role": {
"type": "string",
"enum": ["admin"]
}
}
|
export const status = z.enum(["active", "inactive", "pending"]);
export const role = z.literal("admin");
|
Arrays
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Tags": {
"type": "array",
"items": { "type": "string" }
},
"Matrix": {
"type": "array",
"items": {
"type": "array",
"items": { "type": "number" }
}
}
}
|
export const tags = z.array(z.string());
export const matrix = z.array(z.array(z.number()));
|
Nested Objects
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Company": {
"type": "object",
"properties": {
"name": { "type": "string" },
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
},
"required": ["street", "city"]
}
},
"required": ["name", "address"]
}
}
|
export const company = z.object({
name: z.string(),
address: z.object({
street: z.string(),
city: z.string(),
}),
});
|
Nullable Types
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Article": {
"type": "object",
"properties": {
"title": { "type": "string" },
"publishedAt": {
"type": "string",
"nullable": true
}
},
"required": ["title", "publishedAt"]
}
}
|
export const article = z.object({
title: z.string(),
publishedAt: z.string().nullable(),
});
|
Union Types
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"StringOrNumber": {
"anyOf": [
{ "type": "string" },
{ "type": "number" }
]
},
"Pet": {
"oneOf": [
{
"type": "object",
"properties": {
"type": { "type": "string", "enum": ["cat"] },
"meow": { "type": "boolean" }
},
"required": ["type", "meow"]
},
{
"type": "object",
"properties": {
"type": { "type": "string", "enum": ["dog"] },
"bark": { "type": "boolean" }
},
"required": ["type", "bark"]
}
]
}
}
|
export const stringOrNumber = z.union([z.string(), z.number()]);
export const pet = z.discriminatedUnion("type", [
z.object({
type: z.literal("cat"),
meow: z.boolean(),
}),
z.object({
type: z.literal("dog"),
bark: z.boolean(),
}),
]);
|
Record Types (Additional Properties)
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Metadata": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"Config": {
"type": "object",
"properties": {
"id": { "type": "string" }
},
"required": ["id"],
"additionalProperties": { "type": "number" }
}
}
|
export const metadata = z.record(z.string(), z.string());
export const config = z.object({ id: z.string() }).and(
z.record(z.string(), z.number()),
);
|
References and Recursive Types
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"Category": {
"type": "object",
"properties": {
"name": { "type": "string" },
"parent": { "$ref": "#/components/schemas/Category" }
},
"required": ["name"]
}
}
|
export const category = z.object({
name: z.string(),
parent: z.lazy(() => Category).optional(),
});
|
Type Name Transformations
Schema names are automatically converted to PascalCase:
| Input (OpenAPI Schema) | Zod Schema |
|---|
{
"user-profile": { "type": "string" },
"api_response": { "type": "number" },
"MyType": { "type": "boolean" }
}
|
export const userProfile = z.string();
export const apiResponse = z.number();
export const myType = z.boolean();
|
Testing
Run tests for this generator:
cd gen-zod && deno task test
Or with coverage:
deno task test:coverage
Generate HTML coverage report:
deno task coverage:html
Support
License
MIT.