mrkeyoor.com_
Sat 08 Aug 21:02 UTC
npmUtilsupdated 08 Aug 2026

@valibot/to-json-schema

@valibot/to-json-schema is Valibot's official converter from executable Valibot schemas to portable JSON Schema. It emits draft-07 by default, can target draft-2020-12 or OpenAPI 3.0 Schema Objects, and supports reusable definitions, recursive lazy schemas, metadata, input-versus-output conversion, and custom overrides. It translates structure and many validations, but it does not turn JavaScript transformations or every Valibot-specific rule into equivalent cross-language behavior.

Verdict

The natural converter for a Valibot codebase, with strong target, definition, and override support and unusually honest compatibility documentation. Keep default throw behavior, choose input or output mode deliberately, and test generated schemas because no converter can preserve JavaScript transformations or every validator's semantics.

API stability4/5The main `toJsonSchema`, `toJsonSchemaDefs`, and `toStandardJsonSchema` functions have clear typed contracts, and targets and error modes are explicit string unions. Version 1.7.1 peers with Valibot's stable 1.x line. Type mode, override contexts, custom references, and global definition helpers are marked beta in source, so advanced integrations should expect more movement than basic conversion.
Docs5/5The package README lists supported schemas and actions one by one, labels partial conversions, explains Unicode length differences, format-validator drift, target-specific limitations, input and output pipelines, errors, overrides, metadata, recursion, definitions, OpenAPI references, Standard Schema output, and global storage with concrete examples. Few schema converters document lossy edges this directly.
Maintenance5/5Version 1.7.1 was published in June 2026, and GitHub reports a Valibot monorepo push on August 8, 2026. The project is non-archived, MIT licensed, fully typed, dependency-free at runtime, tested with Vitest and type checking, and released alongside an active core library. The 166 open issues and pull requests cover the full Valibot monorepo rather than only this converter.
Ecosystem4/5The package recorded 4,205,028 downloads in the measured week and directly serves Valibot users producing OpenAPI, code-generation, form, cross-language, and structured-output artifacts. ESM, CommonJS, declarations, zero dependencies, and three target formats ease adoption. Its ecosystem is necessarily bounded by Valibot ^1.4.0, and downstream JSON Schema consumers still vary in draft and format support.

Use it if

  • Valibot is your runtime validator and you need JSON Schema for documentation, code generation, forms, or structured model output
  • You need draft-07, draft-2020-12, or OpenAPI 3.0 output from one schema source
  • You want named definitions and custom reference paths for OpenAPI components
  • You are prepared to test generated schemas in the exact downstream validator or API consumer
Skip it if

Setup reality

Install both packages with npm install valibot @valibot/to-json-schema. Converter 1.7.1 has no runtime dependencies, native build, credentials, or config file, but it requires Valibot ^1.4.0 as a peer. It ships ESM and CommonJS exports, TypeScript declarations, and `sideEffects: false`. `toJsonSchema(schema)` runs synchronously and defaults to draft-07; choose `target` explicitly when another tool expects draft-2020-12 or OpenAPI 3.0. Conversion is not proof of behavioral equivalence. Transform actions have no JSON Schema representation, many JavaScript-specific schemas and validations are unsupported, regex flags cannot be carried over, variant discriminator keys are ignored, and JSON Schema validators may implement formats differently. Unicode length is a particularly real trap: Valibot uses JavaScript string length in UTF-16 code units while JSON Schema counts code points. By default incompatible features throw. `errorMode: 'warn'` or `'ignore'` can keep generation moving, but ignore commonly emits an empty schema or drops an action, which accepts more than the Valibot source. Prefer a deliberate `overrideSchema` or `overrideAction` and regression-test generated output. For transforming pipelines, set `typeMode: 'input'` for request shape or `'output'` for response shape; output mode needs an explicit schema after the last transformation. Named `definitions` make stable references, while lazy schemas can generate numeric definition IDs automatically. `overrideRef` is needed when embedding definitions under an OpenAPI components path. The beta override, type-mode, and global-definition APIs deserve extra upgrade tests. Global definitions are stored in module-level mutable state and have no documented clearing function, so per-call definitions are safer in servers and test suites.

Patterns

Convert a Valibot schema to draft-07convert-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. Set target explicitly when another draft or OpenAPI is required.

Convert required and optional object fieldsconvert-object-schema

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);

Only non-optional properties appear in the generated required array.

Generate JSON Schema draft 2020-12target-draft-2020-12

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

The generated $schema URI changes, but the downstream validator must also support draft 2020-12.

Generate an OpenAPI 3.0 Schema Objecttarget-openapi-3

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

OpenAPI 3.0 output has no $schema property and cannot express every JSON Schema feature, including propertyNames.

Carry title, description, and examplesinclude-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);

Only valid title, description, and examples metadata is converted.

Create stable reusable definitionscreate-named-definitions

const EmailSchema = v.pipe(v.string(), v.email());
const AccountSchema = v.object({email: EmailSchema});

const jsonSchema = toJsonSchema(AccountSchema, {
  definitions: {EmailSchema},
});

Passing the same schema object in definitions lets occurrences become references instead of repeated inline schemas.

Convert a recursive lazy schemaconvert-recursive-schema

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

const jsonSchema = toJsonSchema(CategorySchema);

The lazy getter is executed with undefined as input, and automatic definitions may receive generated numeric IDs.

Generate the accepted input side of a transformdescribe-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 second schema in a pipeline.

Generate the output side of a transformdescribe-transform-output

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

Output mode starts from the last schema; put an explicit schema after the final transform or the output cannot be described safely.

Map a Valibot File to OpenAPI binary inputoverride-unsupported-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'};
    }
  },
});

An override suppresses conversion errors for the matched schema. Confirm that your OpenAPI consumer uses the same representation.

Generate schemas for OpenAPI componentsbuild-openapi-components

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

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

toJsonSchemaDefs returns only the definitions map; insert it under components.schemas yourself.

Keep unsupported conversion failures visiblehandle-conversion-errors

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

Throw is the default and safest CI behavior. Ignore mode can turn unsupported schemas into {}, accepting any value.

Alternatives

PackageRegistryPick it when
zod-to-json-schemanpmYour existing schemas are Zod 3 and you need its established conversion options
@alcyone-labs/zod-to-json-schemanpmYou use Zod 4 and want a maintained fork focused on converting it
@sinclair/typeboxnpmYou want to author JSON Schema objects directly while retaining static TypeScript inference
arktypenpmYou prefer ArkType's runtime and type syntax and can use its own schema interoperability path