Naming convention

In many cases a schema is created and exported together with the inferred type. There are two naming conventions for this procedure that I recommend you to use when working with me. In this guide I will explain both of them and share why I think they might make sense.

You don't have to follow any of these conventions. They are only recommendations.

Convention 1

The first naming convention exports the schema and type with the same name. The advantage of this is that the names are short and the boilerplate is low, since the schema and type can be imported together.

We also recommend to follow the PascalCase naming convention. This means that each word starts with an uppercase letter. This is a common convention for TypeScript types, and since schemas basically provide runtime validation of types, it makes sense to use this convention for schemas as well.


In the following example, a schema is created for a user object. In order to follow the naming convention, the schema and the type are exported with the same name.

import * as v from 'valibot';

export const PublicUser = v.object({
  name: v.string([v.maxLength(30)]),
  email: v.string([]),
  avatar: v.nullable(v.blob()),
  bio: v.string([v.maxLength(1000)]),

export type PublicUser = v.Output<typeof PublicUser>;

The schema and type can then be imported and used together.

import * as v from 'valibot';
import { PublicUser } from './types';

// Use `PublicUser` as a type
const publicUsers: PublicUser[] = [];

  // Use `PublicUser` as a schema
  v.parse(PublicUser, {
    name: 'Jane Doe',
    email: '',
    avatar: null,
    bio: 'Lorem ipsum ...',

Convention 2

The first naming convention can cause naming conflicts with other classes and types. It also causes a problem when you need to export both the input and output types of a schema.

The second naming convention provides a solution. It also follows the PascalCase naming convention, but adds an appropriate suffix to each export. Schemas get the suffix Schema, input types get the suffix Input and output types get the suffix Output.

If there is no difference between the input and output type, the suffix Data can optionally be used to indicate this.

This requires the schema and types to be imported separately, which increases the overhead. However, the naming convention is more precise, flexible, and works in any use case.


In the following example, a schema is created for an image object. In order to follow the naming convention, the schema and the types are exported with different names.

import * as v from 'valibot';

export const ImageSchema = v.object({
  status: v.optional(v.picklist(['public', 'private']), 'private'),
  created: v.optional(, () => new Date()),
  title: v.string([v.maxLength(100)]),
  source: v.string([v.url()]),
  size: v.number([v.minValue(0)]),

export type ImageInput = v.Input<typeof ImageSchema>;
export type ImageOutput = v.Output<typeof ImageSchema>;

The schema and the input and output types can then be imported and used separately.

import * as v from 'valibot';
import { ImageInput, ImageOutput, ImageSchema } from './types';

export function createImage(input: ImageInput): ImageOutput {
  return v.parse(ImageSchema, input);

Do you have ideas for improving these conventions? We welcome your feedback and suggestions. Feel free to create an issue on GitHub.


Thanks to all the contributors who helped make this page better!

  • GitHub profile picture of shairez
  • GitHub profile picture of fabian-hiller


Thanks to our partners who support the project ideally and financially.


Thanks to our GitHub sponsors who support the project financially.

  • GitHub profile picture of dailydotdev
  • GitHub profile picture of ivan-mihalic
  • GitHub profile picture of KATT
  • GitHub profile picture of osdiab
  • GitHub profile picture of Thanaen
  • GitHub profile picture of hyunbinseo
  • GitHub profile picture of caegdeveloper