Zod vs Yup vs Valibot: validação de schema em TypeScript

1. Introdução à validação de schemas no ecossistema TypeScript

1.1. Por que a validação de dados é crítica em aplicações TypeScript

TypeScript oferece segurança de tipos em tempo de compilação, mas dados que chegam de fontes externas — APIs, formulários, arquivos JSON — não têm garantia de tipo. Um campo string pode conter null, um number pode ser NaN. Sem validação em tempo de execução, seu sistema de tipos vira uma ilusão.

1.2. O papel dos schemas na segurança de tipos em tempo de execução

Schemas de validação funcionam como guardiões na fronteira entre o mundo externo (não confiável) e o interno (tipado). Eles verificam, transformam e garantem que os dados estejam no formato esperado antes de serem processados.

1.3. Panorama geral: Zod, Yup e Valibot como alternativas modernas

Três bibliotecas dominam o cenário atual: Yup (a veterana), Zod (a preferida da comunidade) e Valibot (a novata modular). Cada uma tem filosofia, performance e casos de uso distintos.

2. Yup: o veterano consolidado

2.1. Histórico e adoção no ecossistema React/Formik

Yup nasceu em 2017 e se tornou padrão no ecossistema React, especialmente com Formik. Sua API encadeada é intuitiva:

import * as yup from 'yup';

const schema = yup.object({
  nome: yup.string().required('Nome é obrigatório'),
  idade: yup.number().min(18, 'Deve ser maior de idade'),
  email: yup.string().email('Email inválido')
});

2.2. Sintaxe encadeada e validação assíncrona

Yup suporta validação assíncrona nativa, útil para verificar disponibilidade de username:

const schema = yup.string().test('unique', 'Username já existe', async (value) => {
  const result = await checkUsername(value);
  return result.available;
});

2.3. Limitações: inferência de tipos e suporte nativo a TypeScript

Yup foi construído antes de TypeScript se tornar mainstream. A inferência de tipos é limitada e requer castings manuais:

type User = yup.InferType<typeof schema>;
// Funciona, mas perde tipagem em transformações complexas

3. Zod: o padrão de facto moderno

3.1. Inferência de tipos automática e integração com TypeScript

Zod foi projetado para TypeScript desde o início. A inferência é automática e precisa:

import { z } from 'zod';

const UserSchema = z.object({
  nome: z.string().min(1, 'Nome obrigatório'),
  idade: z.number().min(18),
  email: z.string().email()
});

type User = z.infer<typeof UserSchema>;
// User é inferido como { nome: string; idade: number; email: string }

3.2. API declarativa e transformações de dados

Zod permite transformações encadeadas de forma elegante:

const DataSchema = z.string().transform((str) => str.toUpperCase());
const result = DataSchema.parse('hello'); // 'HELLO'

3.3. Ecossistema: plugins, integrações e casos de uso típicos

Zod possui integrações com React Hook Form, tRPC, e geração automática de schemas OpenAPI via zod-to-openapi.

4. Valibot: a alternativa modular e leve

4.1. Filosofia modular: tree-shaking e tamanho de bundle reduzido

Valibot permite importar apenas os validadores necessários, reduzindo drasticamente o bundle:

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

const UserSchema = object({
  nome: string([minLength(1, 'Nome obrigatório')]),
  idade: number([minValue(18)]),
  email: string([email()])
});

4.2. API funcional vs. orientada a objetos

Valibot usa composição funcional em vez de encadeamento, o que favorece tree-shaking e reuso:

const nameValidator = string([minLength(1), maxLength(100)]);
const emailValidator = string([email()]);

const UserSchema = object({
  nome: nameValidator,
  email: emailValidator
});

4.3. Performance e adequação para projetos com restrições de tamanho

Valibot tem bundle ~3KB (vs ~15KB do Zod e ~20KB do Yup), ideal para bibliotecas compartilhadas e microsserviços.

5. Comparação prática: sintaxe e recursos

5.1. Definição de schemas equivalentes nos três frameworks

// Yup
const yupSchema = yup.object({
  nome: yup.string().required(),
  tags: yup.array().of(yup.string()).min(1)
});

// Zod
const zodSchema = z.object({
  nome: z.string().min(1),
  tags: z.array(z.string()).min(1)
});

// Valibot
const valibotSchema = object({
  nome: string([minLength(1)]),
  tags: array(string(), [minLength(1)])
});

5.2. Validação de objetos aninhados, arrays e uniões

// Zod com união discriminada
const ResultSchema = z.discriminatedUnion('status', [
  z.object({ status: z.literal('success'), data: z.string() }),
  z.object({ status: z.literal('error'), message: z.string() })
]);

5.3. Mensagens de erro personalizadas e internacionalização

Todas as três bibliotecas suportam mensagens customizadas, mas Zod e Valibot oferecem melhor tipagem para i18n.

6. Integração com frameworks e ferramentas

6.1. Uso com React Hook Form e bibliotecas de formulários

// React Hook Form + Zod
const { register, handleSubmit } = useForm({
  resolver: zodResolver(UserSchema)
});

Yup tem integração nativa com Formik; Zod e Valibot funcionam via adaptadores.

6.2. Validação em APIs REST e GraphQL

Zod é amplamente usado com tRPC para validação automática de inputs. Valibot pode ser usado com Hono ou Elysia para APIs leves.

6.3. Geração de tipos TypeScript a partir de schemas

Zod e Valibot geram tipos automaticamente. Yup requer yup.InferType com limitações.

7. Performance e trade-offs em produção

7.1. Benchmark de tempo de validação e consumo de memória

Em benchmarks de validação de objetos complexos, Zod é ~2x mais rápido que Yup. Valibot é comparável ao Zod para schemas simples e mais rápido com tree-shaking.

7.2. Impacto no bundle final e carregamento da aplicação

Biblioteca Bundle (min+gzip)
Yup ~20KB
Zod ~15KB
Valibot ~3KB

7.3. Quando escolher cada biblioteca: cenários recomendados

  • Yup: projetos legados com Formik, equipes acostumadas com API encadeada
  • Zod: novos projetos TypeScript, APIs GraphQL/tRPC, necessidade de inferência precisa
  • Valibot: bibliotecas públicas, microsserviços, projetos com restrição de tamanho

8. Conclusão e guia de decisão

8.1. Resumo das forças e fraquezas de cada ferramenta

Critério Yup Zod Valibot
Inferência TS Limitada Excelente Boa
Bundle Grande Médio Pequeno
Ecossistema Formik tRPC, React Hook Form Emergente
Performance Lento Rápido Rápido

8.2. Matriz de decisão para diferentes perfis de projeto

  • Projeto novo com TypeScript: Zod
  • Projeto React existente com Formik: Yup
  • Biblioteca open source: Valibot
  • API de alto desempenho: Zod ou Valibot

8.3. Tendências futuras e evolução da validação de schemas em TypeScript

A tendência é modularização e desempenho. Valibot representa o futuro com tree-shaking nativo. Zod continua evoluindo com suporte a padrões como JSON Schema. Yup tende a perder espaço para alternativas mais modernas.

Referências