0
# JSON Schema Conversion
1
2
Convert Zod schemas to JSON Schema format for documentation and interoperability.
3
4
## JSON Schema Conversion
5
6
```typescript { .api }
7
function toJSONSchema<T extends ZodTypeAny>(
8
schema: T,
9
options?: {
10
name?: string;
11
$refStrategy?: "root" | "relative" | "none";
12
basePath?: string[];
13
effectStrategy?: "input" | "output";
14
}
15
): JSONSchema7;
16
```
17
18
**Examples:**
19
```typescript
20
import { z } from "zod";
21
22
// Basic conversion
23
const schema = z.object({
24
name: z.string(),
25
age: z.number(),
26
});
27
28
const jsonSchema = z.toJSONSchema(schema);
29
// {
30
// type: "object",
31
// properties: {
32
// name: { type: "string" },
33
// age: { type: "number" }
34
// },
35
// required: ["name", "age"],
36
// additionalProperties: false
37
// }
38
39
// With name
40
const jsonSchema = z.toJSONSchema(schema, { name: "User" });
41
// Adds "$id": "User" to the schema
42
43
// Reference strategy
44
const jsonSchema = z.toJSONSchema(schema, {
45
$refStrategy: "root" // or "relative" or "none"
46
});
47
```
48
49
## Supported Schema Types
50
51
```typescript
52
// Primitives
53
z.string() // { type: "string" }
54
z.number() // { type: "number" }
55
z.boolean() // { type: "boolean" }
56
z.null() // { type: "null" }
57
58
// String formats
59
z.email() // { type: "string", format: "email" }
60
z.url() // { type: "string", format: "uri" }
61
z.uuid() // { type: "string", format: "uuid" }
62
63
// Number constraints
64
z.number().min(0) // { type: "number", minimum: 0 }
65
z.number().max(100) // { type: "number", maximum: 100 }
66
z.number().int() // { type: "integer" }
67
68
// String constraints
69
z.string().min(3) // { type: "string", minLength: 3 }
70
z.string().max(20) // { type: "string", maxLength: 20 }
71
z.string().regex(/^[a-z]+$/) // { type: "string", pattern: "^[a-z]+$" }
72
73
// Arrays
74
z.array(z.string()) // { type: "array", items: { type: "string" } }
75
z.array(z.number()).min(1) // { type: "array", items: { type: "number" }, minItems: 1 }
76
77
// Objects
78
z.object({
79
name: z.string(),
80
age: z.number().optional(),
81
})
82
// {
83
// type: "object",
84
// properties: {
85
// name: { type: "string" },
86
// age: { type: "number" }
87
// },
88
// required: ["name"]
89
// }
90
91
// Enums
92
z.enum(["a", "b", "c"])
93
// { type: "string", enum: ["a", "b", "c"] }
94
95
// Unions
96
z.union([z.string(), z.number()])
97
// { anyOf: [{ type: "string" }, { type: "number" }] }
98
99
// Nullable
100
z.string().nullable()
101
// { anyOf: [{ type: "string" }, { type: "null" }] }
102
103
// Optional
104
z.string().optional()
105
// { type: "string" } (not in required array)
106
107
// Default values
108
z.string().default("hello")
109
// { type: "string", default: "hello" }
110
```
111
112
## Descriptions
113
114
```typescript
115
const schema = z.object({
116
name: z.string({ description: "User's full name" }),
117
age: z.number({ description: "User's age in years" }),
118
email: z.email({ description: "User's email address" }),
119
});
120
121
const jsonSchema = z.toJSONSchema(schema);
122
// Properties will include description fields
123
```
124
125
## Complex Schemas
126
127
```typescript
128
// Nested objects
129
const AddressSchema = z.object({
130
street: z.string(),
131
city: z.string(),
132
country: z.string(),
133
});
134
135
const UserSchema = z.object({
136
name: z.string(),
137
address: AddressSchema,
138
});
139
140
const jsonSchema = z.toJSONSchema(UserSchema);
141
142
// Discriminated unions
143
const MessageSchema = z.discriminatedUnion("type", [
144
z.object({ type: z.literal("text"), content: z.string() }),
145
z.object({ type: z.literal("image"), url: z.string().url() }),
146
]);
147
148
const jsonSchema = z.toJSONSchema(MessageSchema);
149
// Converts to JSON Schema with oneOf
150
151
// Arrays of objects
152
const UsersSchema = z.array(z.object({
153
id: z.string().uuid(),
154
name: z.string(),
155
email: z.email(),
156
}));
157
158
const jsonSchema = z.toJSONSchema(UsersSchema);
159
```
160
161
## Common Patterns
162
163
```typescript
164
// API documentation generation
165
const APISchema = z.object({
166
method: z.enum(["GET", "POST", "PUT", "DELETE"]),
167
path: z.string(),
168
body: z.object({
169
data: z.any(),
170
}).optional(),
171
headers: z.record(z.string(), z.string()).optional(),
172
});
173
174
const apiJsonSchema = z.toJSONSchema(APISchema, {
175
name: "APIRequest",
176
});
177
178
// Save as JSON file for OpenAPI spec
179
import fs from "fs";
180
fs.writeFileSync("api-schema.json", JSON.stringify(apiJsonSchema, null, 2));
181
182
// Generate documentation
183
const schemas = {
184
User: z.toJSONSchema(UserSchema),
185
Post: z.toJSONSchema(PostSchema),
186
Comment: z.toJSONSchema(CommentSchema),
187
};
188
189
// Form validation schema for UI libraries
190
const FormSchema = z.object({
191
name: z.string().min(2),
192
email: z.email(),
193
age: z.number().int().min(18),
194
subscribe: z.boolean().default(false),
195
});
196
197
const formJsonSchema = z.toJSONSchema(FormSchema);
198
// Use with react-jsonschema-form or similar
199
200
// OpenAPI integration
201
const RouteSchema = z.object({
202
params: z.object({ id: z.string() }),
203
query: z.object({ page: z.coerce.number().optional() }),
204
body: UserSchema,
205
});
206
207
const openAPISchema = {
208
parameters: z.toJSONSchema(RouteSchema.shape.params),
209
requestBody: {
210
content: {
211
"application/json": {
212
schema: z.toJSONSchema(RouteSchema.shape.body),
213
},
214
},
215
},
216
};
217
```
218
219
## Limitations
220
221
```typescript
222
// Not all Zod features map to JSON Schema:
223
// - Refinements (custom validation)
224
// - Transformations
225
// - Async validation
226
// - Custom error messages
227
228
// These features are Zod-specific and cannot be represented in JSON Schema
229
230
// For documentation purposes, use descriptions
231
const schema = z.object({
232
password: z.string()
233
.min(8, { description: "Must be at least 8 characters" })
234
.refine((val) => /[A-Z]/.test(val), "Must contain uppercase")
235
// refine won't appear in JSON Schema, only min constraint
236
});
237
```
238
239
## Effect Strategy
240
241
```typescript
242
// For schemas with transformations
243
const TransformSchema = z.string().transform((s) => s.length);
244
245
// Input schema (before transformation)
246
const inputSchema = z.toJSONSchema(TransformSchema, {
247
effectStrategy: "input"
248
});
249
// { type: "string" }
250
251
// Output schema (after transformation)
252
const outputSchema = z.toJSONSchema(TransformSchema, {
253
effectStrategy: "output"
254
});
255
// { type: "number" }
256
```
257
258
## Use Cases
259
260
1. **API Documentation**: Generate OpenAPI/Swagger specs
261
2. **Form Validation**: JSON Schema for form libraries
262
3. **Code Generation**: Generate types in other languages
263
4. **Validation Libraries**: Use with JSON Schema validators
264
5. **Documentation**: Auto-generate schema documentation
265
6. **Interoperability**: Share schemas with non-TypeScript systems
266