npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@valibot/to-json-schema

v1.4.0

Published

The official JSON schema converter for Valibot

Readme

Valibot to JSON Schema

Utility to convert Valibot schemas to JSON schema (draft 07).

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

toJsonSchema(v.string()); // { type: "string" }

This package is particularly popular for:

  • API Documentation: Generate OpenAPI specifications from your Valibot schemas
  • Code Generation: Create client SDKs and types from your validation schemas
  • LLM Integration: Generate structured outputs for Large Language Models
  • Schema Sharing: Share validation logic between different programming languages

Some Valibot features can't be mapped to JSON schema. For example, transformation actions have no equivalent in JSON schema. Also, some Valibot schemas or validations are too JS-specific and do not have an equivalent JSON schema attribute.

Supported features

Note: Converted schemas may behave slightly differently in JSON schema validators (especially for string format) because their implementation is different from Valibot's.

| Schema | Status | Note | | ---------------- | ------ | ------------------------------------------------------------------- | | any | ✅ | | | array | ✅ | | | boolean | ✅ | | | enum | ✅ | | | exactOptional | ✅ | | | intersect | ✅ | | | lazy | ⚠️ | The .getter function is always executed with undefined as input | | literal | ⚠️ | Only JSON compatible values are supported | | looseObject | ✅ | | | looseTuple | ✅ | | | null | ✅ | | | nullable | ✅ | | | nullish | ✅ | | | number | ✅ | | | objectWithRest | ✅ | | | object | ✅ | | | optional | ✅ | | | picklist | ⚠️ | Only JSON compatible values are supported | | record | ⚠️ | Only plain string schemas for the key of the record are supported | | strictObject | ✅ | | | strictTuple | ✅ | | | string | ✅ | | | tupleWithRest | ✅ | | | tuple | ✅ | | | union | ✅ | | | undefinedable | ✅ | | | unknown | ✅ | | | variant | ⚠️ | The discriminator key will be ignored |

| Actions | Status | Note | | -------------- | ------ | ----------------------------------------------------------- | | base64 | ✅ | | | bic | ✅ | | | cuid2 | ✅ | | | decimal | ✅ | | | description | ✅ | | | digits | ✅ | | | email | ✅ | | | emoji | ✅ | | | empty | ✅ | | | entries | ✅ | | | hexadecimal | ✅ | | | hexColor | ✅ | | | integer | ✅ | | | ipv4 | ✅ | | | ipv6 | ✅ | | | isoDate | ✅ | | | isoDateTime | ✅ | | | isoTime | ✅ | | | isoTimestamp | ✅ | | | length | ⚠️ | Only in combination with string and array schema | | maxEntries | ✅ | | | maxLength | ⚠️ | Only in combination with string and array schema | | maxValue | ⚠️ | Only in combination with number schema | | metadata | ⚠️ | Only for valid title, description and examples values | | minEntries | ✅ | | | minLength | ⚠️ | Only in combination with string and array schemas | | minValue | ⚠️ | Only in combination with number schema | | multipleOf | ✅ | | | nanoid | ✅ | | | nonEmpty | ✅ | | | octal | ✅ | | | regex | ⚠️ | RexExp flags are not supported in JSON schema | | title | ✅ | | | ulid | ✅ | | | url | ✅ | | | uuid | ✅ | | | value | ✅ | |

Configurations

| Option | Type | Note | | -------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | typeMode | 'ignore' \| 'input' \| 'output' | Whether to convert the input or output type of the Valibot schema to JSON Schema. | | errorMode | 'throw' \| 'warn' \| 'ignore' | The policy for handling incompatible schemas and actions. | | definitions | Record<string, GenericSchema> | The schema definitions for constructing recursive schemas. If not specified, the definitions are generated automatically. | | overrideSchema | (context: OverrideSchemaContext) => JSONSchema7 \| null \| undefined | Overrides the JSON Schema conversion for a specific Valibot schema. | | ignoreActions | string[] | The actions that should be ignored during the conversion. | | overrideAction | (context: OverrideActionContext) => JSONSchema7 \| null \| undefined | Overrides the JSON Schema reference for a specific Valibot action. | | overrideRef | (context: OverrideRefContext) => string \| null \| undefined | Overrides the JSON Schema reference for a specific reference ID. |

Type mode

The typeMode configuration controls whether to convert the input or output type of the Valibot schema to JSON Schema.

  • When set to 'input', conversion stops before the first potential type transformation action or second schema in any pipeline.
  • When set to 'output', conversion of any pipelines starts from the last schema in the pipeline. Therefore, the output type must be specified explicitly with a schema after the last type transformation action.
  • When set to 'ignore' (default), the entire pipeline is converted.

This is particularly useful when defining API endpoints where external developers need different schema information for requests vs responses:

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

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

toJsonSchema(ValibotSchema, { typeMode: 'input' });

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "string",
//   pattern: "^[+-]?(?:\\d*\\.)?\\d+$"
// }

toJsonSchema(ValibotSchema, { typeMode: 'output' });

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "number",
//   maximum: 100
// }

Error mode

The errorMode configuration controls how the converter handles unsupported schemas and actions. By default, the error mode is set to 'throw'. To force the conversion of unsupported Valibot features, you can set it to 'ignore'.

Unsupported schemas usually return an empty JSON schema ({}) and unsupported actions are usually ignored.

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

toJsonSchema(v.file(), { errorMode: 'ignore' }); // {}

toJsonSchema(v.pipe(v.string(), v.creditCard()), { errorMode: 'ignore' }); // { type: "string" }

Override functions

The package provides powerful override capabilities to customize the JSON Schema conversion process. You can override the conversion of specific schemas, actions, or references.

Override schema conversion

Handle unsupported schemas or customize conversion behavior:

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

const ValibotSchema = v.object({ createdAt: v.date() });

toJsonSchema(ValibotSchema, {
  overrideSchema(context) {
    if (context.valibotSchema.type === 'date') {
      return { type: 'string', format: 'date-time' };
    }
  },
});

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "object",
//   properties: {
//     createdAt: { type: "string" format: "date-time" }
//   },
//   required: ["createdAt"]
// }

Override reference IDs

Customize reference IDs for OpenAPI or other specifications:

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

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

toJsonSchemaDefs(
  { UserSchema },
  { overrideRef: (context) => `#/schemas/${context.referenceId}` }
);

Enhanced metadata support

Use the generic metadata action to add title, description, and examples to your schemas or the individual titleand description actions:

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

const ValibotSchema = v.pipe(
  v.string(),
  v.email(),
  v.metadata({
    title: 'Email Schema',
    description: 'A schema that validates email addresses.',
    examples: ['[email protected]'],
  })
);

toJsonSchema(ValibotSchema);

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "string",
//   format: "email",
//   title: "Email Schema",
//   description: "A schema that validates email addresses.",
//   examples: ["[email protected]"]
// }

Definitions

Nested and recursive schemas can be broken in multiple reusable definitions.

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

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

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "object",
//   properties: {
//     email: {
//       $ref: "#/$defs/EmailSchema"
//     }
//   },
//   required: ["email"],
//   $defs: {
//     EmailSchema: {
//       type: "string",
//       format: "email"
//     }
//   }
// }

Definitions are not required for converting lazy schemas. Missing definitions will be generated automatically.

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

const StringSchema = v.string();
toJsonSchema(v.object({ key: v.lazy(() => StringSchema) }));

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "object",
//   properties: {
//     key: {
//       $ref: "#/$defs/0"
//     }
//   },
//   required: ["key"],
//   $defs: {
//     0: {
//       type: "string"
//     }
//   }
// }

Additional functions

toJsonSchemaDefs

Converts only the provided Valibot schema definitions to JSON Schema definitions, without wrapping them in a root schema. This is particularly useful for OpenAPI specifications where you need only the schema definitions.

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

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

toJsonSchemaDefs({ EmailSchema, UserSchema });

// {
//   EmailSchema: {
//     type: "string",
//     format: "email"
//   },
//   UserSchema: {
//     type: "object",
//     properties: {
//       name: {
//         type: "string"
//       },
//       email: {
//         $ref: "#/$defs/EmailSchema"
//       }
//     },
//     required: ["name", "email"]
//   }
// }

OpenAPI integration

For OpenAPI specifications, you can customize reference IDs:

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

const ValibotSchema1 = v.string();
const ValibotSchema2 = v.number();
const ValibotSchema3 = v.tuple([ValibotSchema1, ValibotSchema2]);

toJsonSchemaDefs(
  { ValibotSchema1, ValibotSchema2, ValibotSchema3 },
  { overrideRef: (context) => `#/schemas/${context.referenceId}` }
);

// {
//   ValibotSchema1: { type: "string" },
//   ValibotSchema2: { type: "number" },
//   ValibotSchema3: {
//     type: "array",
//     items: [
//       { $ref: "#/schemas/ValibotSchema1" },
//       { $ref: "#/schemas/ValibotSchema2" }
//     ],
//     minItems: 2
//   }
// }

Global definitions

For advanced use cases, you can manage global schema definitions that will be automatically used when converting schemas. This is particularly useful for larger projects with many reusable schemas.

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

const ValibotSchema1 = v.string();
const ValibotSchema2 = v.number();

addGlobalDefs({ ValibotSchema1, ValibotSchema2 });

const ValibotSchema3 = v.tuple([ValibotSchema1, ValibotSchema2]);

toJsonSchema(ValibotSchema3);

// {
//   $schema: "http://json-schema.org/draft-07/schema#",
//   type: "array",
//   items: [
//     { $ref: "#/$defs/ValibotSchema1" },
//     { $ref: "#/$defs/ValibotSchema2" }
//   ],
//   minItems: 2,
//   $defs: {
//     ValibotSchema1: { type: "string" },
//     ValibotSchema2: { type: "number" }
//   }
// }

You can also convert global definitions directly using toJsonSchemaDefs:

const globalDefs = getGlobalDefs();
if (globalDefs) {
  const schemaDefs = toJsonSchemaDefs(globalDefs);
}