mrkeyoor.com_
Wed 23 Sept 00:36 UTC
npmUtilsupdated 22 Sept 2026

@valibot/to-json-schema review

@valibot/to-json-schema turns Valibot schemas into draft-07, draft-2020-12, or OpenAPI 3.0 schema objects. That is useful when Valibot validates application data but another system needs a portable description for API docs, forms, code generation, or structured output. Conversion has limits: JavaScript transforms and several Valibot checks have no exact JSON Schema form. Version 1.7.1 fixes references for definition names containing `/` or `~` by encoding those characters as JSON Pointer tokens.

Verdict

@valibot/to-json-schema 1.7.1 installed in 2.3 seconds, occupied 2 MB, and produced a 3.2 KB gzipped browser bundle in our sandbox, with 0 audit findings. Install it for a Valibot stack that needs draft-07, draft-2020-12, or OpenAPI 3.0 output, but keep conversion errors on and test every generated contract that crosses a system boundary.

We installed it

Lab card: what happened when we installed @valibot/to-json-schemaScreenshot of @valibot/to-json-schema documentation
Install✓ · 2.3s2 packages on disk · 2 MB
ImportESM import works · require() works · ESM package with exports map
Browser3.2 KBgzipped (11.7 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @valibot/to-json-schema install cleanly?

Yes. In a fresh container with an empty cache, npm install @valibot/to-json-schema finished in 2 seconds, leaving 2 packages and 2 MB on disk. npm audit reported no known vulnerabilities.

How much does @valibot/to-json-schema add to a browser bundle?

3.2 KB gzipped (11.7 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does @valibot/to-json-schema work with both ESM and CommonJS?

Yes. Both import '@valibot/to-json-schema' and require('@valibot/to-json-schema') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does @valibot/to-json-schema include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@valibot/to-json-schema or zod-to-json-schema: which should you use?

zod-to-json-schema: Use it for an existing Zod 3 schema set that cannot move to Valibot. @valibot/to-json-schema 1.7.1 installed in 2.3 seconds, occupied 2 MB, and produced a 3.2 KB gzipped browser bundle in our sandbox, with 0 audit findings.

When should you not use @valibot/to-json-schema?

Your rules depend on transformations or JavaScript-only checks: the converter cannot express those operations as JSON Schema

API stability4/5Version 1.7.1 exposes typed `toJsonSchema`, `toJsonSchemaDefs`, and `toStandardJsonSchema` entry points through an exports map, and its target and error choices are string unions. The package accepts Valibot ^1.4.0 as its single peer. Its declaration files label type-mode controls, override contexts, reference customization, and global-definition helpers as beta, so code built around those extension points needs upgrade tests even within the 1.x line.
Docs5/5The package README names every supported Valibot schema and action, marks partial conversions, and lists target-specific omissions. It also explains Unicode length differences, validator-dependent formats, input and output modes, recursion, definitions, metadata, errors, and custom overrides with runnable examples. The warning that transforms have no JSON Schema equivalent gives readers a concrete boundary before they publish generated output.
Maintenance5/5Version 1.7.1 was published on June 8, 2026, and the open-circle/valibot repository was pushed on August 22, 2026. The repository is active rather than archived, has an MIT license, and shows 8,957 stars. The current patch fixed JSON Pointer encoding for definition names containing `/` and `~`, backed by a focused source change and tests instead of an unexplained version bump.
Ecosystem4/5npm recorded 4,629,931 downloads for the measured week, and the package serves the Valibot 1.x ecosystem through its declared ^1.4.0 peer. It supports CommonJS and ESM consumers, ships types, and emits three documented targets used by API and tooling stacks. Adoption outside Valibot is limited because the input must be a Valibot schema, and downstream validators still differ in supported drafts and format behavior.

Use it if

  • Your application already validates with Valibot and must publish JSON Schema or OpenAPI 3.0 descriptions
  • You need separate schema descriptions for the input or output side of a transforming Valibot pipeline
  • You need reusable definitions or recursive lazy schemas represented with references
  • You can test the generated result in the same validator, form tool, or API consumer used in production
Skip it if

Setup reality

Our install of 1.7.1 finished in 2.3 seconds and left 2 packages using 2 MB on disk. npm audit found 0 known vulnerabilities. The converter itself has 0 direct dependencies and 1 peer dependency, Valibot ^1.4.0. Its 172 KB package includes TypeScript declarations, an exports map, and working require() and ESM import entry points.

toJsonSchema is synchronous and needs no credentials or config file. It emits draft-07 unless target is set to draft-2020-12 or openapi-3.0. Our browser build measured 11.7 KB minified and 3.2 KB gzipped. OpenAPI 3.0 has narrower vocabulary, so records cannot emit propertyNames, and greater-than or less-than checks have no direct output there.

Conversion errors throw by default. Keeping that default exposes unsupported file schemas, transforms, regex flags, and other rules during a build. warn continues with a console warning, while ignore can replace an unsupported schema with {} or omit an action. For pipelines containing transformations, choose typeMode: 'input' or 'output'; output mode needs a concrete schema after the last transform.

Named definitions produce $defs references, and lazy schemas may receive generated numeric IDs. Version 1.7.1 correctly escapes / and ~ in those reference tokens. Custom reference paths are needed when definitions live under OpenAPI components. The declaration files mark global definitions and several override hooks as beta. Global definitions also live in module-level state, so per-call definitions are easier to isolate in servers and tests.

Patterns

Convert a schema with the default draft convert-basic-schema

import {toJsonSchema} from '@valibot/to-json-schema';
import * as v from 'valibot';

const schema = toJsonSchema(v.string());
console.log(schema.$schema, schema.type);

draft-07 is the default target. Set `target` when the receiving tool expects another dialect.

Preserve required and optional object fields convert-object-fields

const UserSchema = v.object({
  id: v.pipe(v.string(), v.uuid()),
  name: v.pipe(v.string(), v.minLength(1)),
  age: v.optional(v.pipe(v.number(), v.minValue(0))),
});

const jsonSchema = toJsonSchema(UserSchema);

The generated `required` array contains `id` and `name`; `age` remains optional.

Emit draft 2020-12 target-draft-2020-12

const jsonSchema = toJsonSchema(UserSchema, {
  target: 'draft-2020-12',
});

This changes the `$schema` dialect to draft 2020-12. The validator consuming it must support that draft too.

Emit an OpenAPI 3.0 schema object target-openapi-3

const openApiSchema = toJsonSchema(
  v.nullable(v.string()),
  {target: 'openapi-3.0'},
);
// {type: 'string', nullable: true}

OpenAPI 3.0 uses `nullable: true` and omits `$schema`; features such as record `propertyNames` are unavailable in this target.

Include documentation metadata attach-schema-metadata

const EmailSchema = v.pipe(
  v.string(),
  v.email(),
  v.metadata({
    title: 'Email',
    description: 'Primary contact address',
    examples: ['jane@example.com'],
  }),
);

const jsonSchema = toJsonSchema(EmailSchema);

Valid `title`, `description`, and `examples` metadata is copied into the generated schema.

Reference a definition whose name contains pointer characters escape-definition-references

const ProfileSchema = v.object({name: v.string()});

const jsonSchema = toJsonSchema(ProfileSchema, {
  definitions: {'user/profile~v1': ProfileSchema},
});
// $ref: '#/$defs/user~1profile~0v1'

Version 1.7.1 encodes `/` as `~1` and `~` as `~0` inside generated JSON Pointer references.

Convert a recursive lazy schema convert-recursive-schema

const CategorySchema = v.object({
  name: v.string(),
  children: v.array(v.lazy(() => CategorySchema)),
});

const jsonSchema = toJsonSchema(CategorySchema);

The converter invokes the lazy getter with `undefined` and may create a generated numeric definition ID.

Describe the input side of a transform describe-transform-input

const AmountSchema = v.pipe(
  v.string(),
  v.decimal(),
  v.transform(Number),
  v.number(),
  v.maxValue(100),
);

const inputSchema = toJsonSchema(AmountSchema, {typeMode: 'input'});

Input mode stops before the first possible type transformation or the second schema in the pipeline.

Describe the output side of a transform describe-transform-output

const outputSchema = toJsonSchema(AmountSchema, {
  typeMode: 'output',
});

Output mode starts at the last schema. A transform without a following schema leaves no dependable output shape to convert.

Represent a file upload in OpenAPI override-file-schema

const UploadSchema = v.object({file: v.file()});

const schema = toJsonSchema(UploadSchema, {
  target: 'openapi-3.0',
  overrideSchema({valibotSchema}) {
    if (valibotSchema.type === 'file') {
      return {type: 'string', format: 'binary'};
    }
  },
});

`file` lacks a direct conversion, so the override supplies the OpenAPI binary-string representation.

Build an OpenAPI component map build-openapi-components

import {toJsonSchemaDefs} from '@valibot/to-json-schema';

const schemas = toJsonSchemaDefs(
  {Email: EmailSchema, User: UserSchema},
  {
    target: 'openapi-3.0',
    overrideRef: ({referenceId}) =>
      `#/components/schemas/${referenceId}`,
  },
);

`toJsonSchemaDefs` returns the definitions map only; assign it to `components.schemas` in the OpenAPI document.

Stop publication when conversion is incomplete fail-on-unsupported-rules

try {
  const schema = toJsonSchema(v.file());
  publish(schema);
} catch (error) {
  console.error('Schema conversion failed', error);
  process.exitCode = 1;
}

Throwing is the default. `errorMode: 'ignore'` can turn an unsupported schema into `{}`, which accepts every JSON value.

Alternatives

PackageRegistryPick it when
zod-to-json-schemanpmUse it for an existing Zod 3 schema set that cannot move to Valibot.
@alcyone-labs/zod-to-json-schemanpmUse this maintained fork when your schemas are on Zod 4.
@sinclair/typeboxnpmChoose it when JSON Schema should be the authored source and TypeScript types should follow from it.
arktypenpmConsider it when ArkType already owns runtime validation and its schema export fits the downstream consumer.

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.