or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-schemas.mdcoercion.mdcollections.mderrors.mdindex.mdiso-datetime.mdjson-schema.mdlocales.mdnumber-formats.mdparsing.mdprimitives.mdrefinements.mdstring-formats.mdtransformations.mdunions-intersections.mdutilities.mdwrappers.md

json-schema.mddocs/

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