valibot

repository·main·Indexed 27 days ago

https://github.com/open-circle/valibot

A modular and type-safe schema library for validating structural data. It features a functional API designed for small bundle sizes and tree-shaking. The ecosystem includes utilities for converting Valibot schemas into standard JSON Schema formats (via @valibot/to-json-schema) and codemods for migrating to v0.31.0 or converting Zod schemas to Valibot.

Tokens
185.7K
Snippets
637
Records
1.4K
Agent score
93%

What's inside valibot

  1. Introduction to Valibot

    main

    Valibot is a modular, type-safe schema library designed for validating data at runtime (e.g., server inputs, forms, or configuration files). It is dependency-free and can run in any JavaScript environment.

    Key features include:

    • Static Type Inference: Fully type-safe with automatic TypeScript type generation.
    • Modular Design: Uses small, independent functions to enable tree-shaking, which can reduce bundle sizes by up to 95% compared to libraries like Zod.
    • Small Footprint: Bundle sizes can start at less than 700 bytes.
    • Extensible: The functional API allows for easy extension with external code.
  2. Get started with Valibot

    main
    Valibot is a modular, dependency-free schema validation library designed for small bundle sizes and full type safety. It uses a functional API where small, independent functions are composed to create schemas. This modularity allows bundlers to perform tree-shaking, ensuring only the code you actually use is included in your production build.
  3. Understand Valibot's modular design and tree-shaking

    main

    Valibot uses a modular design based on small, independent functions rather than large objects with many methods. This architecture allows bundlers to use static import statements to perform effective tree-shaking. Only the specific functions you import (e.g., v.string(), v.email()) are included in your production bundle, significantly reducing bundle size compared to libraries that rely on monolithic objects.

    import * as v from 'valibot'; // Only the functions used will be bundled
    
    const LoginSchema = v.object({
      email: v.pipe(
        v.string(),
        v.nonEmpty('Please enter your email.'),
        v.email('The email address is badly formatted.')
      ),
      password: v.pipe(
        v.string(),
        v.nonEmpty('Please enter your password.'),
        v.minLength(8, 'Your password must have 8 characters or more.')
      ),
    });
  4. Understand Valibot's core concepts: Schemas, Methods, and Actions

    main

    Valibot's modular API is built on three distinct pillars. Understanding how they interact is essential for effective use:

    1. Schemas: The foundation. They define a specific data type (e.g., string, object, date). Schemas are independent, reusable, and can be nested to create complex structures.
    2. Methods: Functions used to modify or use a schema. Most methods (like parse) require the schema as the first argument. Some methods, like forward or flatten, operate on actions or issues instead.
    3. Actions: Used to extend a schema's capabilities. Actions are used exclusively within a pipe to add validation, transformation, or metadata (like title or description).
  5. Understand the Open Circle organization

    main

    Open Circle is a GitHub organization that serves as the shared home for Valibot, Formisch, and future projects focused on modularity, type safety, and developer experience. It is a container for related projects rather than a tool or library that you install.

    Key changes for users:

    • Valibot and Formisch repositories have moved from personal GitHub accounts to the open-circle GitHub organization.
    • Repository URLs have changed to reflect the new organization.
    • Sponsorships are now managed transparently via Open Collective.
  6. Explore the Valibot Ecosystem

    main

    Valibot is supported by a wide range of frameworks, libraries, and utilities. You can find integrations for:

    • Frameworks: NestJS, Qwik, and EviKit.
    • API Libraries: Drizzle ORM, GQLoom, Hono, next-safe-action, oRPC, pifying-orm, tRPC, upfetch, and valifetch.
    • AI Libraries: AI SDK.
    • Form Libraries: @rvf/valibot, conform, Formisch, mantine-form-valibot-resolver, maz-ui, pifying-view, React Hook Form, regle, Superforms, svelte-jsonschema-form, TanStack Form, VeeValidate, and vue-valibot-form.
    • Component Libraries: Nuxt UI.
    • Utilities: @valibot/i18n, ArkEnv, fastify-type-provider-valibot, valibot-env, valibotx, and more.
  7. Understand Valibot's current API design and mental model

    main

    Valibot's current API is built on four main concepts:

    1. Schemas: Validate data types (e.g., string, number, object).
    2. Methods: Small utilities used to modify or use a schema (e.g., brand, transform).
    3. Validations: Checks performed within a schema's pipe argument (e.g., email, minLength).
    4. Transformations: Changes made to the data, which can occur either within the pipe argument or via the transform() method.

    Current Usage Patterns:

    • Validations via array in pipe argument:
    const EmailSchema = string([toTrimmed(), email(), endsWith('@example.com')]);
    • Transformations via transform() method:
    const NumberSchema = transform(string([toTrimmed(), decimal()]), (input) => {
      return parseInt(input);
    });
    • Nesting methods:
    const LengthSchema = brand(
      transform(optional(string(), ''), (input) => input.length),
      'Length'
    );
  8. Understand Valibot's impact on Edge Runtime cold starts

    main

    Valibot is designed with a fine-grained, function-based API that enables superior tree-shaking compared to class-based libraries like Zod. In edge environments (e.g., Cloudflare Workers, Vercel Edge Functions, Deno Deploy), smaller bundle sizes directly reduce the amount of code the runtime must load, parse, and evaluate during a cold start.

    In comparative experiments, Valibot's gzipped bundle was found to be ~9.8x smaller than Zod's for an identical schema, which reduces initialization overhead during deployments and traffic spikes.

  9. Handle missing keys in object pipes with optionalAsync

    main

    When using optionalAsync inside a pipeAsync, the pipe actions (like transformAsync or checkAsync) only execute if a default_ value is provided or if the key is present in the input.

    If you want transformations to run even when a key is missing from an object, you must provide a default value to optionalAsync.

    const SchemaWithoutDefault = v.objectAsync({
      isActive: v.pipeAsync(
        v.optionalAsync(v.string()),
        v.transformAsync(async (value) => value === 'true') // Does not run for missing keys
      ),
    }); // Output type: { isActive?: boolean }
    
    const SchemaWithDefault = v.objectAsync({
      isActive: v.pipeAsync(
        v.optionalAsync(v.string(), 'false'), // Default value provided
        v.transformAsync(async (value) => value === 'true') // Runs for missing keys too
      ),
    }); // Output type: { isActive: boolean }