DEV Community

Alex Spinov
Alex Spinov

Posted on

Valibot Has a Free API You're Not Using

Valibot is a schema validation library that's 98% smaller than Zod. At just 0.5KB minified, it's the lightest validation library with full TypeScript inference.

Why Valibot over Zod?

  • Zod: 13.5KB minified (monolithic)
  • Valibot: 0.5-5KB (tree-shakeable — you only ship what you use)

The Free APIs You're Missing

1. Modular Design — Import Only What You Need

import { object, string, number, email, minLength, parse } from "valibot";

const UserSchema = object({
  name: string([minLength(2)]),
  email: string([email()]),
  age: number(),
});

const user = parse(UserSchema, data);
// Only the functions you import end up in your bundle
Enter fullscreen mode Exit fullscreen mode

2. pipe() — Composable Validation Pipelines

import { pipe, string, transform, regex, toLowerCase, trim } from "valibot";

const Slug = pipe(
  string(),
  trim(),
  toLowerCase(),
  regex(/^[a-z0-9-]+$/),
);

const Price = pipe(
  string(),
  transform((s) => parseFloat(s)),
  number(),
  minValue(0),
);
Enter fullscreen mode Exit fullscreen mode

3. variant() — Discriminated Unions

import { variant, object, literal, string, number } from "valibot";

const EventSchema = variant("type", [
  object({ type: literal("click"), x: number(), y: number() }),
  object({ type: literal("hover"), target: string() }),
  object({ type: literal("input"), value: string() }),
]);
Enter fullscreen mode Exit fullscreen mode

4. Brand Types — Nominal Typing

import { brand, string, uuid, pipe } from "valibot";

const UserId = pipe(string(), uuid(), brand("UserId"));
const OrderId = pipe(string(), uuid(), brand("OrderId"));

type UserId = Output<typeof UserId>;
type OrderId = Output<typeof OrderId>;

// TypeScript prevents: getUser(orderId) — type error!
Enter fullscreen mode Exit fullscreen mode

5. Async Validation — Database Checks in Schema

import { objectAsync, stringAsync, customAsync } from "valibot";

const RegisterSchema = objectAsync({
  email: stringAsync([
    email(),
    customAsync(async (value) => {
      const exists = await db.user.findByEmail(value);
      return !exists;
    }, "Email already registered"),
  ]),
  username: stringAsync([
    minLength(3),
    customAsync(async (value) => {
      const taken = await db.user.findByUsername(value);
      return !taken;
    }, "Username taken"),
  ]),
});
Enter fullscreen mode Exit fullscreen mode

Getting Started

npm install valibot
Enter fullscreen mode Exit fullscreen mode

Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com

Check out my awesome-web-scraping list for the best scraping tools and resources.

Top comments (0)