Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
secondsky avatar

Zod

  • 520 installs
  • 202 repo stars
  • Updated August 4, 2026
  • secondsky/claude-skills

zod is a Claude Code skill that teaches TypeScript-first schema validation and type inference with Zod 4.x for API payloads, forms, environment variables, and runtime-safe parsing.

About

zod is a Claude Code skill from secondsky/claude-skills—part of a 170-skill collection and the tooling-skills plugin suite—that documents Zod 4.x schema validation for TypeScript projects. The skill covers z.object, z.string, z.union, z.discriminatedUnion, refinements, transforms, safeParse error handling, and JSON Schema export for OpenAPI or AI tool contracts. It targets Zod package version 4.1.12 or newer with a 2kb gzipped zero-dependency core, requiring TypeScript 5.5+ and strict compiler settings. Developers reach for zod when validating API requests and responses, parsing environment variables, building react-hook-form or tRPC stacks, or debugging missing validation and type inference issues. The skill metadata is version 2.0.0 last verified 2025-11-17 and installs via tooling-skills@claude-skills rather than legacy per-skill plugin commands in the v2.0+ marketplace layout.

  • zod

Zod by the numbers

  • 520 all-time installs (skills.sh)
  • +18 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #808 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/secondsky/claude-skills --skill zod

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs520
repo stars202
Last updatedAugust 4, 2026
Repositorysecondsky/claude-skills

How do you validate API payloads with Zod 4?

Use zod for development tasks

Who is it for?

TypeScript developers adding runtime validation with automatic type inference for APIs, configs, and forms on Zod 4.1.12+.

Skip if: JavaScript-only codebases without TypeScript strict mode, or projects still locked on Zod 3.x APIs without migration capacity.

When should I use this skill?

User needs Zod schemas, safeParse validation, z.infer types, JSON Schema export, or help debugging Zod 4 validation errors.

What you get

Zod schemas, inferred TypeScript types, safeParse handlers, refinements, transforms, and optional JSON Schema exports.

  • Zod schema definitions
  • Inferred TypeScript types
  • JSON Schema or OpenAPI-ready exports

By the numbers

  • Documents Zod 4.1.12+ with a 2kb gzipped zero-dependency core
  • Part of secondsky/claude-skills 170-skill collection at skill version 2.0.0

Files

SKILL.mdMarkdownGitHub ↗

Zod: TypeScript-First Schema Validation

Overview

Zod is a TypeScript-first validation library that enables developers to define schemas for validating data at runtime while automatically inferring static TypeScript types. With zero dependencies and a 2kb core bundle (gzipped), Zod provides immutable, composable validation with comprehensive error handling.

Installation

bun add zod
# or
bun add zod
# or
bun add zod
# or
yarn add zod

Requirements:

  • TypeScript v5.5+ with "strict": true in tsconfig.json
  • Zod 4.x (4.1.12+)

Important: This skill documents Zod 4.x features. The following APIs require Zod 4 and are NOT available in Zod 3.x:

  • z.codec() - Bidirectional transformations
  • z.iso.date(), z.iso.time(), z.iso.datetime(), z.iso.duration() - ISO format validators
  • z.toJSONSchema() - JSON Schema generation
  • z.treeifyError(), z.prettifyError(), z.flattenError() - New error formatting helpers
  • .meta() - Enhanced metadata (Zod 3.x only has .describe())
  • Unified error parameter - Replaces message, invalid_type_error, required_error, errorMap

For Zod 3.x compatibility or migration guidance, see https://zod.dev

Migrating from Zod v3 to v4

Load `references/migration-guide.md` for complete v3 to v4 migration documentation.

Quick Summary

Zod v4 introduces breaking changes for better performance:

  • Error customization: Use unified error parameter (replaces message, invalid_type_error, required_error)
  • Number validation: Stricter - rejects Infinity and unsafe integers
  • String formats: Now top-level functions (z.email() vs z.string().email())
  • Object defaults: Applied even in optional fields
  • Deprecated APIs: Use .extend() (not .merge()), z.treeifyError() (not error.format())
  • Function validation: Use .implement() method
  • UUID validation: Stricter RFC 9562/4122 compliance

→ Load `references/migration-guide.md` for: Complete breaking changes, migration checklist, gradual migration strategy, rollback instructions

Core Concepts

Basic Usage Pattern

import { z } from "zod";

// Define schema
const UserSchema = z.object({
  username: z.string(),
  age: z.number().int().positive(),
  email: z.string().email(),
});

// Infer TypeScript type
type User = z.infer<typeof UserSchema>;

// Validate data (throws on error)
const user = UserSchema.parse(data);

// Validate data (returns result object)
const result = UserSchema.safeParse(data);
if (result.success) {
  console.log(result.data); // Typed!
} else {
  console.error(result.error); // ZodError
}

Parsing Methods

Use the appropriate parsing method based on error handling needs:

  • `.parse(data)` - Throws ZodError on invalid input; returns strongly-typed data on success
  • `.safeParse(data)` - Returns { success: true, data } or { success: false, error } (no exceptions)
  • `.parseAsync(data)` - For schemas with async refinements/transforms
  • `.safeParseAsync(data)` - Async version that doesn't throw

Best Practice: Use .safeParse() to avoid try-catch blocks and leverage discriminated unions.

Primitive Types

Strings

z.string()                    // Basic string
z.string().min(5)            // Minimum length
z.string().max(100)          // Maximum length
z.string().length(10)        // Exact length
z.string().email()           // Email validation
z.string().url()             // URL validation
z.string().uuid()            // UUID format
z.string().regex(/^\d+$/)    // Custom pattern
z.string().startsWith("pre") // Prefix check
z.string().endsWith("suf")   // Suffix check
z.string().trim()            // Auto-trim whitespace
z.string().toLowerCase()     // Auto-lowercase
z.string().toUpperCase()     // Auto-uppercase

// ISO formats (Zod 4+)
z.iso.date()                 // YYYY-MM-DD
z.iso.time()                 // HH:MM:SS
z.iso.datetime()             // ISO 8601 datetime
z.iso.duration()             // ISO 8601 duration

// Network formats
z.ipv4()                     // IPv4 address
z.ipv6()                     // IPv6 address
z.cidrv4()                   // IPv4 CIDR notation
z.cidrv6()                   // IPv6 CIDR notation

// Other formats
z.jwt()                      // JWT token
z.nanoid()                   // Nanoid
z.cuid()                     // CUID
z.cuid2()                    // CUID2
z.ulid()                     // ULID
z.base64()                   // Base64 encoded
z.hex()                      // Hexadecimal

Numbers

z.number()                   // Basic number
z.number().int()             // Integer only
z.number().positive()        // > 0
z.number().nonnegative()     // >= 0
z.number().negative()        // < 0
z.number().nonpositive()     // <= 0
z.number().min(0)            // Minimum value
z.number().max(100)          // Maximum value
z.number().gt(0)             // Greater than
z.number().gte(0)            // Greater than or equal
z.number().lt(100)           // Less than
z.number().lte(100)          // Less than or equal
z.number().multipleOf(5)     // Must be multiple of 5
z.int()                      // Shorthand for z.number().int()
z.int32()                    // 32-bit integer
z.nan()                      // NaN value

Coercion (Type Conversion)

z.coerce.string()            // Convert to string
z.coerce.number()            // Convert to number
z.coerce.boolean()           // Convert to boolean
z.coerce.bigint()            // Convert to bigint
z.coerce.date()              // Convert to Date

// Example: Parse query parameters
const QuerySchema = z.object({
  page: z.coerce.number().int().positive(),
  limit: z.coerce.number().int().max(100).default(10),
});

// "?page=5&limit=20" -> { page: 5, limit: 20 }

Other Primitives

z.boolean()                  // Boolean
z.date()                     // Date object
z.date().min(new Date("2020-01-01"))
z.date().max(new Date("2030-12-31"))
z.bigint()                   // BigInt
z.symbol()                   // Symbol
z.null()                     // Null
z.undefined()                // Undefined
z.void()                     // Void (undefined)

Complex Types

Objects

const PersonSchema = z.object({
  name: z.string(),
  age: z.number(),
  address: z.object({
    street: z.string(),
    city: z.string(),
    country: z.string(),
  }),
});

type Person = z.infer<typeof PersonSchema>;

// Object methods
PersonSchema.shape                 // Access shape
PersonSchema.keyof()              // Get union of keys
PersonSchema.extend({ role: z.string() })  // Add fields
PersonSchema.pick({ name: true }) // Pick specific fields
PersonSchema.omit({ age: true })  // Omit fields
PersonSchema.partial()            // Make all fields optional
PersonSchema.required()           // Make all fields required
PersonSchema.deepPartial()        // Recursively optional

// Strict vs loose objects
z.strictObject({ ... })           // No extra keys allowed (throws)
z.object({ ... })                 // Strips extra keys (default)
z.looseObject({ ... })            // Allows extra keys

Arrays

z.array(z.string())              // String array
z.array(z.number()).min(1)       // At least 1 element
z.array(z.number()).max(10)      // At most 10 elements
z.array(z.number()).length(5)    // Exactly 5 elements
z.array(z.number()).nonempty()   // At least 1 element

// Nested arrays
z.array(z.array(z.number()))     // number[][]

Tuples

z.tuple([z.string(), z.number()]) // [string, number]
z.tuple([z.string(), z.number()]).rest(z.boolean()) // [string, number, ...boolean[]]

Enums and Literals

// Enum
const RoleEnum = z.enum(["admin", "user", "guest"]);
type Role = z.infer<typeof RoleEnum>; // "admin" | "user" | "guest"

// Literal values
z.literal("exact_value")
z.literal(42)
z.literal(true)

// Native TypeScript enum
enum Fruits {
  Apple,
  Banana,
}
z.nativeEnum(Fruits)

// Enum methods
RoleEnum.enum.admin              // "admin"
RoleEnum.exclude(["guest"])      // Exclude values
RoleEnum.extract(["admin", "user"]) // Include only

Unions

// Basic union
z.union([z.string(), z.number()])

// Discriminated union (better performance & type inference)
const ResponseSchema = z.discriminatedUnion("status", [
  z.object({ status: z.literal("success"), data: z.any() }),
  z.object({ status: z.literal("error"), message: z.string() }),
]);

type Response = z.infer<typeof ResponseSchema>;
// { status: "success", data: any } | { status: "error", message: string }

Intersections

const BaseSchema = z.object({ id: z.string() });
const ExtendedSchema = z.object({ name: z.string() });

const Combined = z.intersection(BaseSchema, ExtendedSchema);
// Equivalent to: z.object({ id: z.string(), name: z.string() })

Records and Maps

// Record: object with typed keys and values
z.record(z.string())             // { [key: string]: string }
z.record(z.string(), z.number()) // { [key: string]: number }

// Partial record (some keys optional)
z.partialRecord(z.enum(["a", "b"]), z.string())

// Map
z.map(z.string(), z.number())    // Map<string, number>
z.set(z.string())                // Set<string>

Advanced Patterns

Load `references/advanced-patterns.md` for complete advanced validation and transformation patterns.

Quick Reference

Refinements (custom validation):

z.string().refine((val) => val.length >= 8, "Too short");
z.object({ password, confirmPassword }).superRefine((data, ctx) => { /* ... */ });

Transformations (modify data):

z.string().transform((val) => val.trim());
z.string().pipe(z.coerce.number());

Codecs (bidirectional transforms - NEW in v4.1):

const DateCodec = z.codec(
  z.iso.datetime(),
  z.date(),
  {
    decode: (str) => new Date(str),
    encode: (date) => date.toISOString(),
  }
);

Recursive Types:

const CategorySchema: z.ZodType<Category> = z.lazy(() =>
  z.object({ name: z.string(), subcategories: z.array(CategorySchema) })
);

Optional/Nullable:

z.string().optional()            // string | undefined
z.string().nullable()            // string | null
z.string().default("default")    // Provides default if undefined

Readonly & Brand:

z.object({ ... }).readonly()     // Readonly properties
z.string().brand<"UserId">()     // Nominal typing

→ Load `references/advanced-patterns.md` for: Complete refinement patterns, async validation, codec examples, composable schemas, conditional validation, performance optimization

Error Handling

Load `references/error-handling.md` for complete error formatting and customization guide.

Quick Reference

Error Formatting Methods:

// For forms
const { fieldErrors } = z.flattenError(error);

// For nested data
const tree = z.treeifyError(error);
const nameError = tree.properties?.user?.properties?.name?.errors?.[0];

// For debugging
console.log(z.prettifyError(error));

Custom Error Messages (three levels):

// 1. Schema-level (highest priority)
z.string({ error: "Custom message" });
z.string().min(5, "Too short");

// 2. Per-parse level
schema.parse(data, { error: (issue) => ({ message: "..." }) });

// 3. Global level
z.config({ customError: (issue) => ({ message: "..." }) });

Localization (40+ languages):

z.config(z.locales.es());  // Spanish
z.config(z.locales.fr());  // French

→ Load `references/error-handling.md` for: Complete error formatting examples, custom error patterns, localization setup, error code reference

Type Inference

Load `references/type-inference.md` for complete type inference and metadata documentation.

Quick Reference

Basic Type Inference:

const UserSchema = z.object({ name: z.string() });
type User = z.infer<typeof UserSchema>; // { name: string }

Input vs Output (for transforms):

const TransformSchema = z.string().transform((s) => s.length);
type Input = z.input<typeof TransformSchema>;   // string
type Output = z.output<typeof TransformSchema>; // number

JSON Schema Conversion:

const jsonSchema = z.toJSONSchema(UserSchema, {
  target: "openapi-3.0",
  metadata: true,
});

Metadata:

// Add metadata
const EmailSchema = z.string().email().meta({
  title: "Email Address",
  description: "User's email address",
});

// Create custom registry
const formRegistry = z.registry<FormFieldMeta>();

→ Load `references/type-inference.md` for: Complete type inference patterns, JSON Schema options, metadata system, custom registries, brand types

Functions

Validate function inputs and outputs:

const AddFunction = z.function()
  .args(z.number(), z.number())  // Arguments
  .returns(z.number());           // Return type

// Implement typed function
const add = AddFunction.implement((a, b) => {
  return a + b; // Type-checked!
});

// Async functions
const FetchFunction = z.function()
  .args(z.string())
  .returns(z.promise(z.object({ data: z.any() })))
  .implementAsync(async (url) => {
    const response = await fetch(url);
    return response.json();
  });

Common Patterns

Environment Variables

const EnvSchema = z.object({
  NODE_ENV: z.enum(["development", "production", "test"]),
  DATABASE_URL: z.string().url(),
  PORT: z.coerce.number().int().positive().default(3000),
  API_KEY: z.string().min(32),
});

// Validate on startup
const env = EnvSchema.parse(process.env);

// Now use typed env
console.log(env.PORT); // number

API Request Validation

const CreateUserRequest = z.object({
  username: z.string().min(3).max(20),
  email: z.string().email(),
  password: z.string().min(8),
  age: z.number().int().positive().optional(),
});

// Express example
app.post("/users", async (req, res) => {
  const result = CreateUserRequest.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({
      errors: z.flattenError(result.error).fieldErrors,
    });
  }

  const user = await createUser(result.data);
  res.json(user);
});

Form Validation

const FormSchema = z.object({
  firstName: z.string().min(1, "First name required"),
  lastName: z.string().min(1, "Last name required"),
  email: z.string().email("Invalid email"),
  age: z.coerce.number().int().min(18, "Must be 18+"),
  agreeToTerms: z.literal(true, {
    errorMap: () => ({ message: "Must accept terms" }),
  }),
});

type FormData = z.infer<typeof FormSchema>;

Partial Updates

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

// For PATCH requests: make everything optional except id
const UpdateUserSchema = UserSchema.partial().required({ id: true });

type UpdateUser = z.infer<typeof UpdateUserSchema>;
// { id: string; name?: string; email?: string }

Composable Schemas

// Base schemas
const TimestampSchema = z.object({
  createdAt: z.date(),
  updatedAt: z.date(),
});

const AuthorSchema = z.object({
  authorId: z.string(),
  authorName: z.string(),
});

// Compose into larger schemas
const PostSchema = z.object({
  id: z.string(),
  title: z.string(),
  content: z.string(),
}).merge(TimestampSchema).merge(AuthorSchema);

Ecosystem Integration

Load `references/ecosystem-integrations.md` for complete framework and tooling integration guide.

Quick Reference

ESLint Plugins:

  • eslint-plugin-zod-x - Enforces best practices
  • eslint-plugin-import-zod - Enforces import style

Framework Integrations:

  • tRPC - End-to-end typesafe APIs
  • React Hook Form - Form validation (see react-hook-form-zod skill)
  • Prisma - Generate Zod from database models
  • NestJS - DTOs and validation pipes

Code Generation:

  • orval - OpenAPI → Zod
  • Hey API - OpenAPI to TypeScript + Zod
  • kubb - API toolkit with codegen

→ Load `references/ecosystem-integrations.md` for: Setup instructions, integration examples, Hono middleware, Drizzle ORM patterns

Troubleshooting

Load `references/troubleshooting.md` for complete troubleshooting guide, performance tips, and best practices.

Quick Reference

Common Issues: 1. TypeScript strict mode required → Enable in tsconfig.json 2. Large bundle size → Use z.lazy() for code splitting 3. Slow async refinements → Cache or debounce 4. Circular dependencies → Use z.lazy() 5. Slow unions → Use z.discriminatedUnion() 6. Transform vs refine confusion → Use .refine() for validation, .transform() for modification

Performance Tips:

  • Use .discriminatedUnion() (5-10x faster than .union())
  • Cache schema instances
  • Use .safeParse() (avoids try-catch overhead)
  • Lazy load large schemas

Best Practices:

  • Define schemas at module level
  • Use type inference (z.infer)
  • Add custom error messages
  • Validate at system boundaries
  • Compose small schemas
  • Document with .meta()

→ Load `references/troubleshooting.md` for: Detailed solutions, performance optimization, best practices, testing patterns

Quick Reference

// Primitives
z.string(), z.number(), z.boolean(), z.date(), z.bigint()

// Collections
z.array(), z.tuple(), z.object(), z.record(), z.map(), z.set()

// Special types
z.enum(), z.union(), z.discriminatedUnion(), z.intersection()
z.literal(), z.any(), z.unknown(), z.never()

// Modifiers
.optional(), .nullable(), .nullish(), .default(), .catch()
.readonly(), .brand()

// Validation
.min(), .max(), .length(), .regex(), .email(), .url(), .uuid()
.refine(), .superRefine()

// Transformation
.transform(), .pipe(), .codec()

// Parsing
.parse(), .safeParse(), .parseAsync(), .safeParseAsync()

// Type inference
z.infer<typeof Schema>, z.input<typeof Schema>, z.output<typeof Schema>

// Error handling
z.flattenError(), z.treeifyError(), z.prettifyError()

// JSON Schema
z.toJSONSchema(schema, options)

// Metadata
.meta(), .describe()

// Object methods
.extend(), .pick(), .omit(), .partial(), .required(), .merge()

When to Load References

Load `references/migration-guide.md` when:

  • Upgrading from Zod v3 to v4
  • Questions about breaking changes
  • Need migration checklist or rollback strategy
  • Errors related to deprecated APIs (.merge(), error.format(), etc.)
  • Number validation issues with Infinity or unsafe integers

Load `references/error-handling.md` when:

  • Need to format errors for forms or UI
  • Implementing custom error messages
  • Questions about z.flattenError(), z.treeifyError(), or z.prettifyError()
  • Setting up localization for error messages
  • Need error code reference or pattern examples

Load `references/advanced-patterns.md` when:

  • Implementing custom refinements or async validation
  • Need bidirectional transformations (codecs)
  • Working with recursive types or self-referential data
  • Questions about .refine(), .transform(), or .codec()
  • Need performance optimization patterns
  • Implementing conditional validation

Load `references/type-inference.md` when:

  • Questions about TypeScript type inference
  • Need to generate JSON Schema for OpenAPI or AI
  • Implementing metadata system for forms or documentation
  • Need custom registries for type-safe metadata
  • Questions about z.infer, z.input, z.output
  • Using brand types for ID safety

Load `references/ecosystem-integrations.md` when:

  • Integrating with tRPC, React Hook Form, Prisma, or NestJS
  • Setting up ESLint plugins for best practices
  • Generating Zod schemas from OpenAPI (orval, Hey API, kubb)
  • Questions about Hono middleware or Drizzle ORM
  • Need framework-specific integration examples

Load `references/troubleshooting.md` when:

  • Encountering TypeScript strict mode errors
  • Bundle size concerns or lazy loading needs
  • Performance issues with large unions or async refinements
  • Questions about circular dependencies
  • Need best practices or testing patterns
  • Confusion between .refine() and .transform()

Additional Resources

  • Official Docs: https://zod.dev
  • GitHub: https://github.com/colinhacks/zod
  • TypeScript Playground: https://zod-playground.vercel.app
  • ESLint Plugin (Best Practices): https://github.com/JoshuaKGoldberg/eslint-plugin-zod-x
  • tRPC Integration: https://trpc.io
  • Ecosystem: https://zod.dev/ecosystem

---

Production Notes:

  • Package version: 4.1.12+ (Zod 4.x stable)
  • Zero dependencies
  • Bundle size: 2kb (gzipped)
  • TypeScript 5.5+ required
  • Strict mode required
  • Last verified: 2025-11-17
  • Skill version: 2.0.0 (Updated with v4.1 enhancements)

What's New in This Version:

  • ✨ Comprehensive v3 to v4 migration guide with breaking changes
  • ✨ Enhanced error customization with three-level system
  • ✨ Expanded metadata API with registry system
  • ✨ Improved error formatting with practical examples
  • ✨ Built-in localization support for 40+ locales
  • ✨ Detailed codec documentation with real-world patterns
  • ✨ Performance improvements and architectural changes explained

Related skills

How it compares

Pick the zod skill over generic TypeScript helpers when you need Zod 4-specific APIs, safeParse patterns, and JSON Schema export guidance.

FAQ

Which Zod version does the zod skill document?

The zod skill documents Zod 4.x, specifically package version 4.1.12 or newer, including APIs that are not available in Zod 3.x such as updated error customization and stricter number validation.

What TypeScript setup does the zod skill require?

The zod skill requires TypeScript 5.5 or newer with strict mode enabled in tsconfig.json so z.infer and runtime validation stay aligned across API, form, and environment variable schemas.

How large is the Zod library covered by the zod skill?

The zod skill notes Zod's zero-dependency core is about 2kb gzipped, making it suitable for production API and form validation without significantly increasing bundle size.

Backend & APIsbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.