zod
Zod valida dados nos limites de API e configuração para que entradas inválidas nunca cheguem à lógica de negócios. Um único esquema fornece verificações em tempo de execução e tipos TypeScript sem desvios.
Busque em todas as páginas da documentação
Zod valida dados nos limites de API e configuração para que entradas inválidas nunca cheguem à lógica de negócios. Um único esquema fornece verificações em tempo de execução e tipos TypeScript sem desvios.
Cartão de receita de referência rápida - pronto para copiar e colar.
import { z } from "zod";
export const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(120),
role: z.enum(["member", "admin"]).default("member"),
});
export type CreateUserInput = z.infer<typeof createUserSchema>;
// Rota Fastify
app.post("/users", async (req, reply) => {
const parsed = createUserSchema.safeParse(req.body);
if (!parsed.success) {
return reply.status(400).send({ errors: parsed.error.flatten() });
}
return createUser(parsed.data);
});Quando usar isso:
process.env na inicialização (veja também Validação de Esquemas de Ambiente e Zod)// src/schemas/order.ts
import { z } from "zod";
export const orderItemSchema = z.object({
sku: z.string().uuid(),
quantity: z.coerce.number().int().positive(),
});
export const createOrderSchema = z.object({
customerId: z.string().uuid(),
items: z.array(orderItemSchema).min(1),
shipBy: z.string().datetime().optional(),
});
export type CreateOrderInput = z.infer<typeof createOrderSchema>;
// src/routes/orders.ts
import type { FastifyInstance } from "fastify";
import { createOrderSchema } from "../schemas/order.js";
export async function orderRoutes(app: FastifyInstance): Promise<void> {
app.post("/orders", async (req, reply) => {
const result = createOrderSchema.safeParse(req.body);
if (!result.success) {
req.log.warn({ validation: result.error.flatten() }, "invalid_order");
return reply.status(400).send({
error: "validation_failed",
details: result.error.flatten().fieldErrors,
});
}
const order = await createOrder(result.data);
return reply.status(201).send(order);
});
}// src/workers/email.worker.ts
import { z } from "zod";
const emailJobSchema = z.object({
to: z.string().email(),
templateId: z.string(),
vars: z.record(z.string()),
});
export async function processEmailJob(raw: unknown): Promise<void> {
const job = emailJobSchema.parse(raw); // lança → BullMQ retry/DLQ
await sendEmail(job);
}Comportamentos chave:
safeParse para HTTP - mapeia para 400 sem lançar exceçãoparse para workers - permite que a fila tente novamente em mensagens corrompidasz.coerce.number() para query strings e variáveis de ambiente.refine() para regras entre campos (ex: shipBy deve ser uma data futura)| Abordagem | Prós | Contras |
|---|---|---|
| Zod | Inferência TS, composável, ótima DX | Custo de tempo de execução em caminhos críticos (geralmente negligenciável) |
| Apenas JSON Schema | Nativo do Fastify, exportação OpenAPI | Sem tipos TS compartilhados sem geração de código |
| Verificações manuais if | Zero dependências | Desvia dos tipos; padrões não testáveis |
| class-validator (Nest) | Ecossistema Nest | Magia de decoradores; menos portável |
@fastify/type-provider-typebox ou convertem Zod para JSON Schema para serialização de resposta.nestjs-zod ou pipes globais com DTOs Zod.import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { createOrderSchema } from "./order.js";
describe("createOrderSchema", () => {
it("rejeita itens vazios", () => {
const result = createOrderSchema.safeParse({
customerId: "550e8400-e29b-41d4-a716-446655440000",
items: [],
});
assert.equal(result.success, false);
});
});__fixtures__/invalid-orders.json.Valide nas fronteiras (HTTP, env, fila, webhooks externos). Dentro da lógica de domínio, confie em valores tipados. Não analise o mesmo objeto três vezes por requisição.
Mapeie error.flatten().fieldErrors para o seu padrão de erro de API. Nunca retorne o stack ou issues brutos do ZodError em produção.
Use Zod como fonte da verdade e gere OpenAPI com zod-to-openapi ou mantenha JSON Schema paralelo para documentação pública. Escolha uma fonte - não edite ambas manualmente.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026