zod-to-json-schema review
zod-to-json-schema 3.25.2 converts Zod v3 schemas into JSON Schema draft 7, draft 2019-09, OpenAPI 3.0, or an experimental OpenAI-oriented shape. It can emit references for repeated or recursive definitions, translate common string and numeric checks, alter additional-property handling, and let callbacks override or post-process generated nodes. The important current fact is retirement: the maintainer ended active maintenance in November 2025 because Zod 4 now generates JSON Schema itself, and GitHub marks the repository archived. Version 3.25.2 only raises its Zod 3 peer floor to 3.25.28 after earlier 3.25 patches caused out-of-memory problems or lacked the `/v3` compatibility import.
Do not add zod-to-json-schema to a new project: it is archived, maintenance has ended, and Zod 4 contains the intended replacement. Keep 3.25.2 only where v3 compatibility or exact historical output still matters, lock it, test emitted schemas, and schedule removal.
We installed it
| Install | ✓ · 0.7s | 7 packages on disk · 8 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package with exports map |
| Browser | 18.7 KB | gzipped (76.6 KB minified), bundled with esbuild |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does zod-to-json-schema install cleanly?
Yes. In a fresh container with an empty cache, npm install zod-to-json-schema finished in 0.7s, leaving 7 packages and 8 MB on disk. npm audit reported no known vulnerabilities.
How much does zod-to-json-schema add to a browser bundle?
18.7 KB gzipped (76.6 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does zod-to-json-schema work with both ESM and CommonJS?
Yes. Both import 'zod-to-json-schema' and require('zod-to-json-schema') worked in Node 22 in our run. The package is published as CommonJS with an exports map.
Does zod-to-json-schema include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
zod-to-json-schema or zod: which should you use?
zod: Use Zod 4's built-in z.toJSONSchema() for new work and migrations from this archived converter. Do not add zod-to-json-schema to a new project: it is archived, maintenance has ended, and Zod 4 contains the intended replacement.
When should you not use zod-to-json-schema?
This is a new Zod 4 project. Zod now provides z.toJSONSchema() in the maintained core package, which is the successor named in this repository's deprecation notice.
Use it if
- A pinned dependency still owns Zod v3 schemas and replacing its converter is outside the current change scope.
- An existing production path already depends on this package's exact reference layout, OpenAPI 3.0 mode, callback options, or OpenAI target and has regression fixtures for the output.
- A Zod 4 project must temporarily convert schemas deliberately authored through `zod/v3` while a staged migration is underway.
- You are auditing a transitive install and need to understand why an agent, MCP, or API tool emits a particular JSON Schema shape.
- This is a new Zod 4 project. Zod now provides `z.toJSONSchema()` in the maintained core package, which is the successor named in this repository's deprecation notice.
- A maintained dependency is required. The repository is archived, active maintenance ended in November 2025, and new converter bugs or future Zod changes will not receive fixes here.
- You intend to pass native Zod 4 schemas. The peer range accepts Zod 4, but the README says 3.25 only converts v3 schemas created through the `zod/v3` compatibility entry.
- Transforms or preprocess effects define the value sent to consumers. JSON Schema cannot recover a transform's runtime output type, and optional-property detection may call preprocess logic with `undefined` during conversion.
- Patch updates must be behavior-preserving by policy. The README explicitly says the project does not follow semantic versioning and notes that features have appeared in patch releases.
Setup reality
We installed zod-to-json-schema 3.25.2 in a fresh Node 22 Bookworm container. npm completed in 0.7 seconds, left 7 packages, and used 8 MB. The package has no direct dependencies, one peer dependency, and 656 KB unpacked under the ISC license. npm audit found zero known vulnerabilities. Both require() and ESM import worked, and TypeScript declarations are bundled. Our full import built to 76.6 KB minified and 18.7 KB gzipped.
Install Zod separately and respect the peer floor ^3.25.28 || ^4. That ^4 range does not mean v4 schema support. In a Zod 4 dependency tree, import z from zod/v3 for every schema passed to this converter. Version 3.25.2 raised the v3 minimum because earlier 3.25 releases either triggered an out-of-memory problem or removed the compatibility alias. Mixing constructors from native v4 and the v3 compatibility layer can survive installation and fail when conversion runs.
Default output is JSON Schema draft 7. Naming a schema wraps it in a definitions collection and returns a root reference. Objects usually emit additionalProperties: false; some downstream providers want the keyword absent or impose their own strict-object rules. Reference strategies change output size and recursion behavior. With $refStrategy: 'none', repeated structures are copied and recursive branches can degrade to an unconstrained schema. Snapshot the exact emitted document consumed by an API instead of checking only TypeScript compilation.
Conversion describes what Zod validates on input. A transform's output function is runtime code, so the generated schema can describe the wrong side for downstream consumers. The OpenAI target is marked experimental, relative JSON pointers have poor resolver support, and draft 2020-12 is not officially supported. Override callbacks use a special ignoreOverride sentinel; returning undefined removes the node. Because the project is archived, keep any remaining use behind fixtures and plan a Zod 4 migration rather than adding new option combinations.
Patterns
Generate draft 7 from a Zod v3 object convert-basic-schema
import { z } from 'zod/v3';
import { zodToJsonSchema } from 'zod-to-json-schema';
const User = z.object({
name: z.string().min(2),
age: z.number().int().optional(),
});
const jsonSchema = zodToJsonSchema(User);Use the v3 entry when Zod 4 is installed. Default output targets draft 7 and normally disallows unknown object properties through `additionalProperties: false`.
Place a named schema behind a reference name-definition
const jsonSchema = zodToJsonSchema(User, {
name: 'User',
definitionPath: '$defs',
});Naming changes the root shape to a `$ref` plus a definitions collection. Confirm the receiving library resolves references before enabling it.
Emit the OpenAPI 3.0 dialect target-openapi-3
const schema = zodToJsonSchema(User, {
target: 'openApi3',
$refStrategy: 'none',
});OpenAPI 3.0 differs from newer JSON Schema behavior, including nullable representation. OpenAPI 3.1 consumers should normally use regular JSON Schema instead.
Generate the package's OpenAI shape target-openai
const Args = z.object({
city: z.string(),
units: z.enum(['c', 'f']).optional(),
});
const parameters = zodToJsonSchema(Args, {
target: 'openAi',
$refStrategy: 'none',
});The README labels this target experimental. Validate the emitted schema against the exact API and model endpoint before caching or publishing it.
Reference one sub-schema in several places share-definitions
const Address = z.object({
street: z.string(),
postalCode: z.string(),
});
const Order = z.object({ billing: Address, shipping: Address });
const schema = zodToJsonSchema(Order, {
definitions: { Address },
});Explicit definitions can prevent repeated copies. The reference path also depends on `definitionPath`, schema naming, and base-path options.
Inline output for a consumer without `$ref` inline-references
const schema = zodToJsonSchema(Order, {
$refStrategy: 'none',
});Inlining expands repeated branches and cannot expand recursion forever. Inspect recursive schemas because the converter may replace the recursive point with an unconstrained object.
Remove additional-property keywords omit-additional-properties
const schema = zodToJsonSchema(User, {
allowedAdditionalProperties: undefined,
rejectedAdditionalProperties: undefined,
});These options do not override an explicit `.catchall()` schema. Omitting the keyword changes how downstream validators apply their own defaults.
Carry supported Zod messages into AJV metadata emit-error-messages
const Email = z
.string()
.email('Invalid email')
.min(5, 'Too short');
const schema = zodToJsonSchema(Email, {
errorMessages: true,
});The emitted `errorMessage` keyword is an AJV extension, not standard JSON Schema. It has an effect only when the consumer installs and enables compatible support.
Expand metadata from a JSON description add-json-metadata
import { jsonDescription, zodToJsonSchema } from 'zod-to-json-schema';
const City = z.string().describe(JSON.stringify({
title: 'City',
description: 'Delivery city',
examples: ['Ahmedabad', 'Pune'],
}));
const schema = zodToJsonSchema(City, { postProcess: jsonDescription });This is a Zod v3 workaround that treats description text as JSON. Zod 4 has its own metadata and JSON Schema generation path.
Replace one generated property override-node
import { ignoreOverride, zodToJsonSchema } from 'zod-to-json-schema';
const schema = zodToJsonSchema(User, {
override(definition, refs) {
if (refs.currentPath.join('/') === '#/properties/age') {
return { type: 'integer', minimum: 0 };
}
return ignoreOverride;
},
});Return `ignoreOverride` when no replacement is intended. Returning `undefined` deliberately filters the node out of the generated document.
Keep legacy schemas isolated in a Zod 4 tree convert-v3-under-zod-4
import { z as z3 } from 'zod/v3';
import { zodToJsonSchema } from 'zod-to-json-schema';
const LegacyInput = z3.object({
id: z3.string().uuid(),
});
const schema = zodToJsonSchema(LegacyInput);Version 3.25.2 requires a Zod release where the `/v3` alias exists. Do not pass a schema constructed by the native Zod 4 API.
Use Zod 4 without this converter migrate-to-zod-4
import { z } from 'zod';
const User = z.object({
name: z.string().min(2),
age: z.number().int().optional(),
});
const schema = z.toJSONSchema(User, {
target: 'draft-7',
});Zod 4 output is not guaranteed to match this package byte for byte. Diff representative recursive, transformed, optional, and metadata-heavy schemas against every downstream consumer.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| zod | npm | Use Zod 4's built-in `z.toJSONSchema()` for new work and migrations from this archived converter. |
| zod-openapi | npm | Use it when the maintained output is an OpenAPI document with Zod-backed components and operations rather than standalone JSON Schema. |
| @asteasolutions/zod-to-openapi | npm | Use it when an existing Zod codebase needs explicit OpenAPI metadata, registries, and document generation. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

