How the json-schema-to-zod Utility Works for Type Conversion in Composio

The json-schema-to-zod utility converts JSON Schema definitions into Zod schemas by recursively parsing schema nodes through specialized parsers that map JSON Schema keywords to Zod methods, enabling runtime validation and TypeScript type inference.

The json-schema-to-zod package in the ComposioHQ/composio repository provides a robust bridge between JSON Schema definitions and Zod validation schemas. This TypeScript utility enables developers to generate runtime-validated Zod schemas directly from standard JSON Schema specifications, ensuring type safety across the Composio SDK ecosystem.

Architecture of the json-schema-to-zod Converter

The conversion pipeline operates through three distinct stages: schema normalization, recursive shape building, and parser dispatch.

Entry Point and Schema Normalization

The primary function jsonSchemaToZod in [src/json-schema-to-zod.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/json-schema-to-zod.ts) serves as the public API. It accepts a JSON Schema object and optional configuration flags (such as strict mode), resolves $ref pointers, and normalizes composite keywords like allOf, anyOf, and oneOf before delegation.

The Shape Builder Pattern

The jsonSchemaToZodShape function implements the core recursion logic. It traverses the normalized schema tree, inspecting the type keyword and other schema properties to determine which specialized parser should handle the current node. This function returns a Zod-compatible shape object that can be passed to z.object() or other Zod constructors.

Specialized Parser Modules

Individual parsers located in src/parsers/ handle specific JSON Schema types:

  • parseString.ts: Maps format (email, uuid, etc.), minLength, maxLength, and pattern to corresponding Zod string methods like .email(), .uuid(), .min(), .max(), and .regex().
  • parseNumber.ts: Translates minimum, maximum, exclusiveMinimum, exclusiveMaximum, and multipleOf to Zod number constraints such as .min(), .max(), and .multipleOf().
  • parseObject.ts: Constructs Zod object schemas from properties and required arrays, handling additionalProperties through .strict() or .passthrough() modifiers.
  • parseArray.ts: Converts items, minItems, maxItems, and uniqueItems into Zod array validations using .array(), .min(), .max(), and custom refinements.
  • parseEnum.ts: Creates z.enum([...]) constructs from JSON Schema enum arrays.
  • parseOneOf.ts, parseAnyOf.ts, parseAllOf.ts: Compose Zod unions (z.union) and intersections (z.intersection) to represent complex type combinations.
  • parseIfThenElse.ts: Implements conditional schema logic using Zod refinements and unions to handle JSON Schema's if/then/else constructs.

Utility Helpers and Modifiers

The src/utils/ directory contains helper functions that abstract repetitive Zod construction patterns:

  • extend-schema.ts: Applies Zod modifiers like .default(), .describe(), and .optional() based on schema properties such as default, description, and nullable.
  • its.ts: Provides type-guard utilities for safe schema inspection.
  • omit.ts: Safely omits keys from object schemas during partial transformations.

Converting JSON Schema to Zod in Practice

The following examples demonstrate practical usage patterns for the utility.

Basic Object Conversion

import { jsonSchemaToZod } from '@composio/json-schema-to-zod';

const userSchema = {
  type: 'object',
  required: ['id', 'email'],
  properties: {
    id: { type: 'string', format: 'uuid' },
    email: { type: 'string', format: 'email' },
    age: { type: 'integer', minimum: 0 }
  },
  additionalProperties: false
};

const zodUser = jsonSchemaToZod(userSchema);
// Generates: z.object({
//   id: z.string().uuid(),
//   email: z.string().email(),
//   age: z.number().int().min(0)
// }).strict()

Accessing Raw Shape Objects

For advanced use cases requiring direct manipulation of the Zod shape before object construction:

import { jsonSchemaToZodShape } from '@composio/json-schema-to-zod';

const shape = jsonSchemaToZodShape(userSchema);
// Returns the raw shape object for custom z.object() wrapping

Strict Mode Validation

To enforce exact object matching without unknown keys:

const strictZod = jsonSchemaToZod(userSchema, { strict: true });
// Equivalent to .strict() modifier on the resulting Zod schema

Provider Integration

The utility integrates throughout the Composio SDK to validate tool parameters:

import { jsonSchemaToZodSchema } from '@composio/core';

// Within provider implementations (OpenAI, LangChain, Claude Agent SDK)
const inputZod = jsonSchemaToZodSchema(tool.inputParameters);
const validatedArgs = inputZod.parse(runtimeArguments);

Key Source Files in the Repository

File Purpose
[src/json-schema-to-zod.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/json-schema-to-zod.ts) Core API exposing jsonSchemaToZod and jsonSchemaToZodShape functions
[src/parsers/parse-object.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/parsers/parse-object.ts) Object schema parsing with support for required fields and additionalProperties
[src/parsers/parse-string.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/parsers/parse-string.ts) String validation including formats and pattern matching
[src/parsers/parse-number.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/parsers/parse-number.ts) Numeric constraints and integer handling
[src/parsers/parse-enum.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/parsers/parse-enum.ts) Enum type conversion to Zod enums
[src/parsers/parse-one-of.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/parsers/parse-one-of.ts) Union type composition for oneOf schemas
[src/utils/extend-schema.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/utils/extend-schema.ts) Modifier application for defaults and descriptions
[src/types.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/src/types.ts) Internal TypeScript type definitions
[test/json-to-zod.test.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/test/json-to-zod.test.ts) Unit tests for core conversion logic
[test/comprehensive-edge-case-tests.ts](https://github.com/ComposioHQ/composio/blob/next/ts/packages/json-schema-to-zod/test/comprehensive-edge-case-tests.ts) Edge case coverage including nullable and conditional schemas

Summary

  • The json-schema-to-zod utility provides a three-stage conversion pipeline: normalization, shape building, and parser dispatch.
  • Specialized parsers in src/parsers/ handle specific JSON Schema keywords, translating them to equivalent Zod method chains.
  • The shape builder pattern allows extraction of raw Zod shapes for custom object construction or provider integration.
  • Utility helpers manage cross-cutting concerns like defaults, descriptions, and nullable types through the extend-schema.ts module.
  • The package is extensively tested in test/comprehensive-edge-case-tests.ts covering unions, conditionals, and strict mode scenarios.

Frequently Asked Questions

What is the difference between jsonSchemaToZod and jsonSchemaToZodShape?

jsonSchemaToZod returns a complete Zod schema object ready for validation, while jsonSchemaToZodShape returns the raw shape object used internally by z.object(). Use the shape builder when you need to modify the schema structure before final Zod object construction or when integrating with custom Zod utilities.

How does the utility handle JSON Schema references ($ref)?

The entry point in src/json-schema-to-zod.ts normalizes the input schema by resolving $ref pointers and flattening composite keywords (allOf, anyOf, oneOf) before the recursive parsing begins. This ensures the shape builder receives a dereferenced schema tree.

Can the converter handle complex union types and conditional schemas?

Yes. The parseOneOf.ts, parseAnyOf.ts, and parseAllOf.ts parsers generate Zod unions and intersections, while parseIfThenElse.ts implements conditional logic using Zod refinements. The comprehensive test suite in test/comprehensive-edge-case-tests.ts validates these advanced patterns.

Is there a performance difference between strict and non-strict mode?

Strict mode applies the .strict() modifier to object schemas, which adds runtime checks for unknown keys. This incurs minimal overhead during validation but provides stronger type safety. Non-strict mode allows unknown keys to pass through, offering slightly faster validation for objects with variable structures.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →