zod
Define and use Zod schemas for TypeScript-first validation: primitives, objects, arrays, unions, refinements, transform, z.infer, parse, safeParse. Use when validating input, parsing API data, form validation with react-hook-form, or when the user mentions Zod, schema validation, or z.infer.
What this skill does
# Zod
## Overview
Zod is a **TypeScript-first schema validation library** with **static type inference**. Define a schema once; you get both runtime validation and a TypeScript type (via `z.infer`). Zero external dependencies; works in Node and browsers. Ideal for forms (e.g. with react-hook-form), API parsing, env vars, and any untrusted input.
**Requirements**: TypeScript 5.5+ recommended; enable **`strict`** in `tsconfig.json`.
**Install**: Add `zod` via your package manager. See [zod.dev](https://zod.dev).
---
## Quick start
```ts
import { z } from "zod";
const User = z.object({
name: z.string(),
age: z.number().optional(),
});
type User = z.infer<typeof User>;
// { name: string; age?: number }
const data = User.parse(input); // throws ZodError if invalid
const result = User.safeParse(input); // { success: true, data } | { success: false, error }
```
---
## Primitives and common types
| Schema | Type | Notes |
|--------|------|--------|
| `z.string()` | string | |
| `z.number()` | number | |
| `z.boolean()` | boolean | |
| `z.bigint()` | bigint | |
| `z.date()` | Date | |
| `z.undefined()` | undefined | |
| `z.null()` | null | |
| `z.void()` | void | |
| `z.any()` | any | |
| `z.unknown()` | unknown | |
| `z.never()` | never | |
| `z.literal("x")` | literal | |
| `z.enum(["a", "b"])` | union of literals | |
| `z.string().email()` | string | email format |
| `z.string().url()` | string | URL |
| `z.string().uuid()` | string | UUID |
| `z.string().datetime()` | string | ISO datetime |
| `z.number().int()` | number | integer |
| `z.number().min(n).max(m)` | number | range |
| `z.boolean()` / `z.string().transform(...)` | stringbool | "true"/"false" coercion |
Optional: `.optional()` → `T | undefined`. Nullable: `.nullable()` → `T | null`. Nullish: `.nullish()` → `T | null | undefined`. Default: `.default(value)`.
---
## Objects
```ts
const Schema = z.object({
name: z.string(),
age: z.number().optional(),
tags: z.array(z.string()).default([]),
});
type Schema = z.infer<typeof Schema>;
```
- **.shape**: `Schema.shape.name` (access field schema).
- **.keyof()**: `Schema.keyof()` → enum of keys.
- **.extend({ ... })**: Add or override keys.
- **.pick({ name })** / **.omit({ age })**: Subset of keys.
- **.partial()** / **.required({ name })**: Optionalize or require.
- **.strict()**: No extra keys (default in z.object). **z.strictObject** / **z.looseObject** for behavior variants.
- **.catchall(z.string())**: Allow extra keys with a schema.
- **Nested**: `z.object({ user: z.object({ name: z.string() }) })`.
- **Recursive**: `z.lazy(() => Category)` for self-referential structures.
---
## Arrays and tuples
- **Arrays**: `z.array(z.string())`, `z.string().array()`.
- **Tuples**: `z.tuple([z.string(), z.number()])` — fixed length and types.
- **Non-empty**: `.min(1)` or dedicated helpers if available.
---
## Unions and intersections
- **Union**: `z.union([z.string(), z.number()])` or `z.string().or(z.number())`.
- **Discriminated union**: Use a common key (e.g. `type: "a"`) and `z.discriminatedUnion("type", [z.object({ type: z.literal("a"), ... }), ...])`.
- **Intersection**: `z.intersection(A, B)` or `A.and(B)`.
---
## Refinements and transform
- **.refine(fn, message?)**: Custom validation; keep type unchanged.
- **.superRefine**: Multiple issues or async; push to `ctx`.
- **.transform(fn)**: Change output type. Input and output can differ; use `z.input<typeof schema>` and `z.output<typeof schema>` (or `z.infer` for output).
- **.pipe(otherSchema)**: Chain validation/transform (e.g. string → number via `z.string().pipe(z.coerce.number())`).
---
## Parsing and errors
- **.parse(input)**: Returns data or throws **ZodError**.
- **.safeParse(input)**: Returns `{ success: true, data }` or `{ success: false, error: ZodError }`.
- **ZodError**: `error.issues` (array of `{ path, message, code }`), `error.format()` for nested shape.
- **Async**: `.parseAsync` / `.safeParseAsync` for schemas with async refinements or transforms.
---
## Type inference
- **z.infer<typeof schema>**: Output type (after transforms/defaults).
- **z.input<typeof schema>**: Input type (before transforms; useful when input ≠ output).
- **z.output<typeof schema>**: Same as `z.infer` for output type.
```ts
const S = z.string().transform((s) => s.length);
type In = z.input<typeof S>; // string
type Out = z.output<typeof S>; // number
```
---
## Integration: React Hook Form
Use **@hookform/resolvers** with **zodResolver**:
```ts
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
const formSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
type FormValues = z.infer<typeof formSchema>;
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: { email: "", password: "" },
});
```
---
## Best practices
- Prefer **strict** schemas (no extra keys) for API boundaries; use **.passthrough()** only when you need to forward unknown keys.
- Use **.default()** for optional fields with a default value.
- For API/env parsing, use **safeParse** and handle errors; show user-friendly messages from `error.issues`.
- Use **discriminated unions** for variant payloads (e.g. events by `type`).
- Coerce only when safe: `z.coerce.number()`, `z.coerce.boolean()`, or custom `.transform()`.
---
## Common mistakes
- **Forgetting strict**: Keep TypeScript `strict: true`; Zod works best with it.
- **Input vs output**: After `.transform()`, use `z.input<>` / `z.output<>` if the type seen by callers differs.
- **parse in hot path**: Prefer validating once at boundaries (e.g. API handler, form submit) rather than on every render.
- **Overly broad schema**: Prefer specific types (e.g. `.email()`, `.min()`) instead of plain `z.string()` when the domain has rules.
---
## Additional resources
- [reference.md](reference.md) — Official Zod docs links, API sections (primitives, objects, strings, numbers, refinements, etc.), Zod Mini, ecosystem.
- **Official**: https://zod.dev — Introduction, API, basics, ecosystem.
- **API (Zod 4)**: https://zod.dev/api — Full schema types and methods.
- **LLMs / index**: https://zod.dev/llms.txt — Structured doc for tools/agents.
Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.