CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-zod-to-json-schema

Converts Zod schemas to JSON Schema format with support for multiple targets and extensive configuration options

Overview
Eval results
Files

schema-conversion.mddocs/

Schema Conversion

The core functionality of zod-to-json-schema centers around the zodToJsonSchema function, which converts Zod schemas into JSON Schema format. This conversion supports all Zod schema types and provides flexible configuration options.

Main Conversion Function

function zodToJsonSchema<Target extends Targets = "jsonSchema7">(
  schema: ZodSchema<any>,
  options?: Partial<Options<Target>> | string
): (Target extends "jsonSchema7" ? JsonSchema7Type : object) & {
  $schema?: string;
  definitions?: {
    [key: string]: Target extends "jsonSchema7"
      ? JsonSchema7Type
      : Target extends "jsonSchema2019-09"
        ? JsonSchema7Type
        : object;
  };
};

Parameters:

  • schema: The Zod schema to convert
  • options: Configuration options or a string name for the schema

Returns: JSON Schema object with optional $schema and definitions properties

Usage Examples

Basic Conversion

import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";

const userSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1),
  email: z.string().email(),
  age: z.number().int().min(0),
  isActive: z.boolean()
});

const jsonSchema = zodToJsonSchema(userSchema);

Named Schema Conversion

// Using string name (shorthand)
const namedSchema = zodToJsonSchema(userSchema, "User");

// Using options object
const namedSchemaOptions = zodToJsonSchema(userSchema, {
  name: "User",
  target: "jsonSchema7"
});

Complex Schema with References

const addressSchema = z.object({
  street: z.string(),
  city: z.string(),
  zipCode: z.string()
});

const personSchema = z.object({
  name: z.string(),
  address: addressSchema,
  alternateAddresses: z.array(addressSchema).optional()
});

const jsonSchema = zodToJsonSchema(personSchema, {
  name: "Person",
  definitions: {
    Address: addressSchema
  }
});

Supported Zod Schema Types

The conversion supports all Zod schema types through specialized parsers:

Primitive Types

  • ZodString - Converted to JSON Schema string type with validation constraints
  • ZodNumber - Converted to JSON Schema number type with range validation
  • ZodBigInt - Converted to JSON Schema integer type with constraints
  • ZodBoolean - Converted to JSON Schema boolean type
  • ZodDate - Converted based on dateStrategy option
  • ZodNull - Converted to JSON Schema null type
  • ZodUndefined - Converted to JSON Schema with no type (allows undefined)

Collection Types

  • ZodArray - Converted to JSON Schema array type with items schema
  • ZodTuple - Converted to JSON Schema array with fixed items
  • ZodRecord - Converted to JSON Schema object with additionalProperties
  • ZodMap - Converted based on mapStrategy option
  • ZodSet - Converted to unique array type

Composite Types

  • ZodObject - Converted to JSON Schema object with properties and required fields
  • ZodUnion - Converted to JSON Schema with type array or anyOf
  • ZodDiscriminatedUnion - Converted to JSON Schema anyOf with discriminator
  • ZodIntersection - Converted to JSON Schema allOf
  • ZodLiteral - Converted to JSON Schema const or enum
  • ZodEnum - Converted to JSON Schema enum
  • ZodNativeEnum - Converted to JSON Schema enum with native enum values

Modifier Types

  • ZodOptional - Removes property from required array
  • ZodNullable - Adds null to type array
  • ZodDefault - Adds default value to schema
  • ZodReadonly - Passes through to inner type
  • ZodBranded - Passes through to inner type
  • ZodCatch - Passes through to inner type based on strategy

Advanced Types

  • ZodEffects - Handled based on effectStrategy option
  • ZodPipeline - Handled based on pipeStrategy option
  • ZodPromise - Passes through to inner type
  • ZodLazy - Supports recursive schema definitions
  • ZodAny - Converted to open schema
  • ZodUnknown - Converted to open schema
  • ZodNever - Converted to impossible schema
  • ZodNaN - Converted to impossible schema

Target Formats

The library supports multiple target JSON Schema formats:

type Targets = "jsonSchema7" | "jsonSchema2019-09" | "openApi3" | "openAi";

JSON Schema 7 (Default)

  • Full JSON Schema Draft 7 support
  • Adds $schema: "http://json-schema.org/draft-07/schema#"

JSON Schema 2019-09

  • JSON Schema Draft 2019-09 support
  • Adds $schema: "https://json-schema.org/draft/2019-09/schema#"

OpenAPI 3.0

  • Legacy OpenAPI 3.0 compatibility
  • Specific handling for OpenAPI constraints

OpenAI

  • OpenAI strict mode compatibility
  • Converts optional properties to required but nullable
  • Uses JSON Schema 2019-09 as base
  • Warns about unsupported union types at root level

Error Handling

The conversion process handles various edge cases:

  • Recursive schemas: Detected and resolved using $ref
  • Circular references: Handled with reference tracking
  • Unsupported types: ZodFunction, ZodVoid, ZodSymbol return undefined
  • Invalid configurations: Fallback to sensible defaults

String Validation Patterns

The library includes built-in patterns for common string validations:

const zodPatterns = {
  cuid: /^[cC][^\s-]{8,}$/,
  cuid2: /^[0-9a-z]+$/,
  ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
  email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
  emoji: () => RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$", "u"),
  uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
  ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,
  ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,
  ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,
  ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,
  base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
  base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,
  nanoid: /^[a-zA-Z0-9_-]{21}$/,
  jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/
};

These patterns are automatically applied when Zod string schemas use built-in validation methods like .email(), .uuid(), etc.

Install with Tessl CLI

npx tessl i tessl/npm-zod-to-json-schema

docs

advanced-features.md

configuration.md

index.md

schema-conversion.md

types.md

tile.json