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
- Documentação oficial do Zod — Guia completo de uso, exemplos e API de transformações
- Documentação oficial do Yup — Repositório com exemplos de validação assíncrona e integração com Formik
- Documentação oficial do Valibot — Introdução à filosofia modular e tree-shaking
- React Hook Form + Zod resolver — Tutorial de integração entre React Hook Form e Zod
- Benchmark de validação de schemas em TypeScript — Discussão sobre performance entre Zod, Yup e Valibot em cenários reais