Zod vs Valibot vs ArkType: чем валидировать
Валидация — это место, где вкус разработчика встречается с реальными размерами бандла. У нас есть три актуальных кандидата: Zod, Valibot и ArkType. Все три — TypeScript-first, выводят типы из схем, работают в браузере и на сервере. Но устроены и ощущаются они по-разному. Я использовала каждый в проде и расскажу, что выбираю в каких сценариях.
Базовое сравнение
Zod — старший в семье, самый зрелый, самый популярный. Объектно-ориентированный API с цепочкой методов.
Valibot — относительно новый игрок, который делает упор на tree-shakeable функции. Размер схемы определяется тем, какие функции реально используются.
ArkType — синтаксически близкий к TypeScript: схемы пишутся почти как типы. Внутри — мощный движок с inference, недоступным в Zod и Valibot.
Zod: API и пример
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
age: z.number().int().min(18).max(100),
tags: z.array(z.string()).max(5).optional(),
role: z.enum(['admin', 'user', 'guest']),
});
type User = z.infer<typeof UserSchema>;
const result = UserSchema.safeParse(unknownInput);
if (!result.success) {
console.log(result.error.flatten());
} else {
const user: User = result.data;
}API очень дружелюбный. Цепочка методов читается легко. Огромное коммьюнити: интеграции с RHF, Hono, tRPC, Next.js — везде Zod считается дефолтом.
Valibot: API и пример
import * as v from 'valibot';
const UserSchema = v.object({
id: v.pipe(v.string(), v.uuid()),
email: v.pipe(v.string(), v.email()),
age: v.pipe(v.number(), v.integer(), v.minValue(18), v.maxValue(100)),
tags: v.optional(v.pipe(v.array(v.string()), v.maxLength(5))),
role: v.picklist(['admin', 'user', 'guest']),
});
type User = v.InferOutput<typeof UserSchema>;
const result = v.safeParse(UserSchema, unknownInput);API функциональный. Каждая операция — отдельная импортируемая функция. Это даёт tree-shaking: в бандл попадает только то, что реально используется.
ArkType: API и пример
import { type } from 'arktype';
const User = type({
id: 'string',
email: 'string.email',
age: 'number.integer>=18&<=100',
'tags?': 'string[]<=5',
role: "'admin' | 'user' | 'guest'",
});
type UserType = typeof User.infer;
const result = User(unknownInput);
if (result instanceof type.errors) {
console.log(result.summary);
}Синтаксис уникальный — описание как строки в стиле TypeScript-типов. Кому-то нравится моментально, кому-то требует привыкания.
Размер бандла
- Zod, минимальный пример (один объект из 3 полей): ~12 КБ gzip.
- Valibot, тот же пример: ~3.5 КБ gzip.
- ArkType, тот же пример: ~14 КБ gzip.
Valibot ощутимо легче. На клиентских проектах, где валидация нужна для одной формы и десятка полей, разница 8-10 КБ заметна.
На больших схемах размер сходится: Zod ~24 КБ, Valibot ~10-12 КБ, ArkType ~16-18 КБ.
Производительность
На моих бенчмарках (простая схема, 100 000 валидаций):
- Zod: ~410 мс.
- Valibot: ~280 мс.
- ArkType: ~140 мс.
ArkType — самый быстрый за счёт компиляции схем в оптимизированные функции. На горячих путях (валидация запросов в API под нагрузкой) это ощутимо.
Полнота возможностей
Zod — самый полный набор. Discriminated unions, transform, refine, brand, lazy, recursive — всё из коробки.
Valibot — почти полный, но некоторые фичи (lazy, recursive) реализованы менее удобно. Discriminated unions работают, но через более явный API.
ArkType — мощнейший движок инференции, особенно для пересечений типов и сложных условных типов. Но местами синтаксис заставляет лезть в документацию.
Сообщения об ошибках
Zod: подробные ошибки с путями (['user', 'address', 'city']) и кодами. Удобно для UI-форм. Localization через ZodErrorMap.
Valibot: похожий формат, чуть менее богатые метаданные.
ArkType: компактные, но местами менее читаемые. Для UI-форм требует обработки.
Интеграции
Zod — везде. RHF, TanStack Form, tRPC, Hono, Next, Astro Actions — всё работает с Zod. Если ваш стек уже использует одну из этих библиотек — Zod ставится бесплатно.
Valibot — растёт. RHF, TanStack Form поддерживают через адаптеры. tRPC — нужны костыли.
ArkType — пока в догоняющих. Сообщество меньше, интеграций меньше.
TypeScript inference
Zod: почти всегда работает, но на сложных дискриминированных типах иногда возвращает any или слишком широкий тип.
Valibot: похожее поведение.
ArkType: лучшая инференция из трёх. Особенно блестит на дискриминированных union'ах и сложных условных типах. Если у вас сложная business-логика с типами — ArkType удивит в лучшую сторону.
Когда я беру Zod
- Любой проект, где нужно «просто валидировать и больше не думать».
- Стек с tRPC, RHF, Next App Router — всё уже подружено с Zod.
- Команда не хочет учить новый API.
Это мой дефолт.
Когда я беру Valibot
- Лендинг, маленькое SPA, мобильное приложение — там, где размер бандла критичен.
- Edge-функции с холодным стартом — меньше парсинга, быстрее старт.
- Schema используется только в одном месте — tree-shaking даёт максимум.
Когда я беру ArkType
- API на Bun или Node с высоконагруженной валидацией.
- Сложная типовая модель с дискриминированными union'ами и условными типами.
- Команда любит TS и хочет «писать типы вместо схем».
Грабли в Zod
Производительность на больших схемах. Если ты валидируешь огромные структуры под нагрузкой, Zod становится бутылочным горлышком. Решение: либо ArkType, либо валидировать только то, что критично.
Schemas нельзя сериализовать. Если нужно отправить схему по сети (например, для динамической формы), Zod не умеет.
Грабли в Valibot
API меняется. Между минорными версиями переименовывали функции (v.string([v.email()]) → v.pipe(v.string(), v.email())). На больших проектах это значит периодические правки.
Меньше готовых интеграций. Местами приходится писать клей самому.
Грабли в ArkType
Кривая обучения. Синтаксис строк нужно держать в голове, и для сложных кейсов документации иногда не хватает.
Сообщество меньше. На StackOverflow ответов по edge-кейсам пока меньше.
В сухом остатке
Zod — для большинства. Valibot — для маленьких клиентских бандлов. ArkType — для серверной нагрузки и сложных типов.
Я в новом проекте обычно начинаю с Zod, потому что 90% случаев он закрывает идеально. Если позже выясняется, что бандл стал слишком тяжёлым или производительность валидации режет API — мигрирую на Valibot или ArkType. Это занимает день-два.
Что копать дальше
Все три библиотеки развиваются, и через год картина может поменяться. Поставьте все три на маленьком проекте, попробуйте написать схемы — синтаксис, ощущение от API, читаемость кода. Технический выбор часто проигрывает эстетическому: команда быстрее принимает то, что нравится.