Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    SlanyCukr

    zod-v4

    SlanyCukr/zod-v4
    Coding
    1

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    TypeScript-first schema validation library with static type inference and runtime validation

    SKILL.md

    Zod v4 - Schema Validation Skill

    Zod v4 is a TypeScript-first schema declaration and validation library that provides static type inference, runtime validation, and exceptional performance. Version 4 delivers 14x faster parsing and 66% smaller bundles while maintaining full type safety.

    Quick Start

    npm install zod@^4.0.0
    
    import * as z from "zod";
    
    // Basic schema creation and validation
    const UserSchema = z.object({
      id: z.number().int().positive(),
      email: z.email(),
      username: z.string().min(3).max(20),
      age: z.number().int().min(18).optional(),
    });
    
    type User = z.infer<typeof UserSchema>;
    
    // Parse and validate
    const user = UserSchema.parse({
      id: 1,
      email: "user@example.com",
      username: "johndoe",
      age: 25,
    });
    
    // Safe parsing with error handling
    const result = UserSchema.safeParse(input);
    if (!result.success) {
      console.log(result.error);
    }
    

    Common Patterns

    Object Schemas with Validation

    // Comprehensive user validation
    const UserProfile = z.object({
      id: z.number().int().positive(),
      email: z.email(),
      username: z
        .string()
        .min(3, "Username must be at least 3 characters")
        .max(20, "Username cannot exceed 20 characters")
        .regex(/^[a-zA-Z0-9_]+$/, "Only alphanumeric characters and underscores"),
      age: z.number().int().min(13).max(120),
      role: z.enum(["user", "admin", "moderator"]).default("user"),
      bio: z.string().max(500).optional(),
      website: z.url().optional(),
      createdAt: z.date().default(() => new Date()),
    });
    
    // Extending schemas
    const AdminProfile = UserProfile.extend({
      permissions: z.array(z.string()),
      accessLevel: z.number().min(1).max(10),
    });
    

    String Format Validation

    // Built-in format validators
    const Validations = {
      email: z.email(),
      uuid: z.uuidv4(),
      url: z.url(),
      ipv4: z.ipv4(),
      ipv6: z.ipv6(),
      base64: z.base64(),
      jwt: z.jwt(),
    
      // ISO formats
      isoDate: z.iso.date(),
      isoDateTime: z.iso.datetime(),
      isoTime: z.iso.time(),
    
      // Custom email with specific pattern
      strictEmail: z.email({ pattern: z.regexes.rfc5322Email }),
    };
    
    // Template literal validation
    const VersionString = z.templateLiteral([
      z.number(),
      ".",
      z.number(),
      ".",
      z.number(),
    ]);
    
    const CSSValue = z.templateLiteral([
      z.number(),
      z.enum(["px", "em", "rem", "%", "vh", "vw"]),
    ]);
    

    Array and Collection Validation

    // Array with constraints
    const NumberArray = z.array(z.number()).min(1).max(100);
    
    // Tuple validation
    const Coordinates = z.tuple([z.number(), z.number()]);
    const MixedTuple = z.tuple([z.string(), z.number()], z.boolean());
    
    // Set validation
    const UniqueStrings = z.set(z.string()).min(3);
    
    // Map validation
    const UserPermissions = z.map(
      z.string(), // user ID
      z.array(z.string()), // permissions
    );
    
    // Record validation
    const StringToNumber = z.record(z.string(), z.number());
    const StatusRecord = z.record(
      z.enum(["pending", "active", "complete"]),
      z.boolean(),
    );
    

    Union and Discriminated Unions

    // Simple union
    const StringOrNumber = z.union([z.string(), z.number()]);
    
    // Discriminated union for API responses
    const ApiResponse = z.discriminatedUnion("status", [
      z.object({
        status: z.literal("success"),
        data: z.unknown(),
      }),
      z.object({
        status: z.literal("error"),
        error: z.string(),
        code: z.number(),
      }),
      z.object({
        status: z.literal("loading"),
        message: z.string().optional(),
      }),
    ]);
    
    // Nested discriminated unions
    const BaseError = z.object({
      status: z.literal("error"),
      message: z.string(),
    });
    
    const DetailedError = z.discriminatedUnion("code", [
      BaseError.extend({ code: z.literal(400), field: z.string() }),
      BaseError.extend({ code: z.literal(401), realm: z.string() }),
      BaseError.extend({ code: z.literal(500), stack: z.string() }),
    ]);
    

    Custom Refinements and Validation

    // Custom validation with refinements
    const PasswordSchema = z
      .string()
      .min(8, "Password must be at least 8 characters")
      .refine((val) => /[A-Z]/.test(val), "Must contain uppercase letter")
      .refine((val) => /[a-z]/.test(val), "Must contain lowercase letter")
      .refine((val) => /[0-9]/.test(val), "Must contain number")
      .refine((val) => /[^A-Za-z0-9]/.test(val), "Must contain special character");
    
    // Complex validation with superRefine
    const UserRegistration = z
      .object({
        email: z.email(),
        password: z.string(),
        confirmPassword: z.string(),
        age: z.number(),
        termsAccepted: z.boolean(),
      })
      .superRefine((data, ctx) => {
        if (data.password !== data.confirmPassword) {
          ctx.addIssue({
            code: "custom",
            path: ["confirmPassword"],
            message: "Passwords must match",
          });
        }
    
        if (data.age < 18 && !data.termsAccepted) {
          ctx.addIssue({
            code: "custom",
            path: ["termsAccepted"],
            message: "Parental consent required for users under 18",
          });
        }
      });
    

    Transformations and Data Processing

    // Transform data during validation
    const StringToNumber = z
      .string()
      .transform((val) => parseInt(val, 10))
      .refine((val) => !isNaN(val), "Must be a valid number");
    
    const TimestampToDate = z
      .number()
      .transform((timestamp) => new Date(timestamp));
    
    const NormalizeEmail = z.string().transform((val) => val.toLowerCase().trim());
    
    // Overwrite for type-preserving transforms
    const RoundNumber = z.number().overwrite((val) => Math.round(val));
    
    // Pipeline transformations
    const ProcessUrl = z
      .string()
      .transform((val) => val.trim())
      .transform((val) => val.toLowerCase())
      .transform((val) => {
        try {
          return new URL(val);
        } catch {
          throw new Error("Invalid URL format");
        }
      });
    

    Recursive Schemas

    // Recursive category structure
    const Category = z.object({
      id: z.number(),
      name: z.string(),
      get subcategories() {
        return z.array(Category);
      },
    });
    
    // Mutually recursive types
    const User = z.object({
      id: z.number(),
      name: z.string(),
      get posts() {
        return z.array(Post);
      },
    });
    
    const Post = z.object({
      id: z.number(),
      title: z.string(),
      content: z.string(),
      get author() {
        return User;
      },
      get comments() {
        return z.array(Comment);
      },
    });
    
    const Comment = z.object({
      id: z.number(),
      text: z.string(),
      get author() {
        return User.pick({ id: true, name: true });
      },
    });
    

    File Validation

    // File upload validation
    const ImageUpload = z.object({
      avatar: z
        .file()
        .max(5_000_000, "File must be less than 5MB")
        .mime(["image/jpeg", "image/png", "image/webp"], "Must be an image"),
    
      banner: z
        .file()
        .max(10_000_000, "File must be less than 10MB")
        .mime(["image/jpeg", "image/png"], "Must be JPEG or PNG")
        .optional(),
    });
    
    // Document validation
    const DocumentUpload = z
      .file()
      .min(1000, "File must be at least 1KB")
      .max(50_000_000, "File must be less than 50MB")
      .mime([
        "application/pdf",
        "application/msword",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      ]);
    

    Function Validation

    // Define validated functions
    const CalculateTax = z.function({
      input: [z.number().min(0), z.number().min(0).max(1)],
      output: z.number(),
    });
    
    const taxCalculator = CalculateTax.implement((amount, rate) => {
      return amount * rate;
    });
    
    // Async function validation
    const FetchUser = z.function({
      input: [z.number().int().positive()],
      output: z.object({
        id: z.number(),
        name: z.string(),
        email: z.email(),
      }),
    });
    
    const getUser = FetchUser.implementAsync(async (id) => {
      const response = await fetch(`/api/users/${id}`);
      return response.json();
    });
    

    Error Handling

    // Custom error messages
    const CustomValidation = z.object({
      username: z
        .string({
          error: (issue) => {
            if (issue.input === undefined) return "Username is required";
            if (typeof issue.input !== "string") return "Username must be a string";
            return "Invalid username";
          },
        })
        .min(3, "Username must be at least 3 characters"),
    });
    
    // Error handling patterns
    const validateInput = (input: unknown) => {
      const result = UserSchema.safeParse(input);
    
      if (!result.success) {
        const error = result.error;
    
        // Pretty print errors
        console.log(z.prettifyError(error));
    
        // Extract field errors
        const fieldErrors = error.issues.reduce(
          (acc, issue) => {
            const field = issue.path.join(".");
            acc[field] = issue.message;
            return acc;
          },
          {} as Record<string, string>,
        );
    
        return { success: false, errors: fieldErrors };
      }
    
      return { success: true, data: result.data };
    };
    

    Default Values and Coercion

    // Schema with defaults
    const ConfigSchema = z.object({
      theme: z.enum(["light", "dark"]).default("light"),
      notifications: z.boolean().default(true),
      fontSize: z.number().min(10).max(30).default(14),
      timeout: z.number().default(5000),
    });
    
    // Type coercion
    const CoercedConfig = z.object({
      port: z.coerce.number().default(3000),
      https: z.coerce.boolean().default(false),
      maxConnections: z.coerce.number().int().positive().default(100),
    });
    
    // Environment variable parsing
    const EnvSchema = z.object({
      NODE_ENV: z
        .enum(["development", "production", "test"])
        .default("development"),
      PORT: z.coerce.number().default(3000),
      DEBUG: z.stringbool().default("false"),
    });
    

    Zod Mini (Tree-Shakable)

    import * as z from "zod/mini";
    
    // Functional API for smaller bundles
    const OptionalString = z.optional(z.string());
    const StringArray = z.array(z.string());
    const StringOrNumber = z.union([z.string(), z.number()]);
    
    // Check functions for validations
    const ValidatedEmail = z
      .string()
      .check(z.regex(/@/), z.minLength(5), z.maxLength(100));
    
    const PositiveInt = z.number().check(z.int(), z.positive(), z.lt(1000));
    
    const NonEmptyArray = z.array(z.any()).check(z.minSize(1));
    

    Practical Examples

    Form Validation

    // Contact form validation
    const ContactForm = z.object({
      name: z.string().min(1, "Name is required").max(100),
      email: z.email("Please provide a valid email"),
      subject: z.string().min(5, "Subject must be at least 5 characters"),
      message: z.string().min(10, "Message must be at least 10 characters"),
      newsletter: z.boolean().default(false),
    });
    
    // React form integration
    const handleSubmit = (formData: FormData) => {
      const data = {
        name: formData.get("name"),
        email: formData.get("email"),
        subject: formData.get("subject"),
        message: formData.get("message"),
        newsletter: formData.get("newsletter") === "on",
      };
    
      const result = ContactForm.safeParse(data);
      if (!result.success) {
        const errors = result.error.flatten();
        return { errors: errors.fieldErrors };
      }
    
      // Process valid data
      return { success: true, data: result.data };
    };
    

    API Response Validation

    // API response schemas
    const UserResponse = z.object({
      data: z.object({
        id: z.number(),
        name: z.string(),
        email: z.email(),
        createdAt: z.string().transform((val) => new Date(val)),
      }),
      meta: z.object({
        total: z.number(),
        page: z.number(),
        totalPages: z.number(),
      }),
    });
    
    // Typed API client
    const apiClient = {
      async getUser(id: number): Promise<z.infer<typeof UserResponse>["data"]> {
        const response = await fetch(`/api/users/${id}`);
        const data = await response.json();
    
        const result = UserResponse.safeParse(data);
        if (!result.success) {
          throw new Error(`Invalid API response: ${result.error.message}`);
        }
    
        return result.data.data;
      },
    };
    

    Configuration Validation

    // Application configuration
    const AppConfig = z.object({
      server: z.object({
        port: z.coerce.number().min(1).max(65535).default(3000),
        host: z.string().default("localhost"),
        cors: z.boolean().default(true),
      }),
      database: z.object({
        url: z.string(),
        ssl: z.boolean().default(false),
        maxConnections: z.coerce.number().int().positive().default(10),
      }),
      auth: z.object({
        jwtSecret: z.string().min(32),
        tokenExpiry: z.string().default("24h"),
        refreshExpiry: z.string().default("7d"),
      }),
    });
    
    // Load and validate config
    const loadConfig = (configPath: string) => {
      const rawConfig = require(configPath);
      const config = AppConfig.parse(rawConfig);
      return config;
    };
    

    Requirements

    • TypeScript: 4.5+ (recommended for best inference)
    • Runtime: Node.js, browsers, Deno, Bun
    • Bundle size: 5.36kb gzipped (full), 1.88kb gzipped (mini)

    Installation

    # Full Zod v4
    npm install zod@^4.0.0
    
    # For minimal bundle size
    npm install zod@^4.0.0
    # Then import from "zod/mini"
    

    Key Features

    • Static Type Inference: Automatic TypeScript type generation from schemas
    • Runtime Validation: Comprehensive input validation with detailed errors
    • Performance: 14x faster parsing than v3, optimized for production
    • Tree Shakable: Zod Mini provides 85% bundle size reduction
    • Template Literals: Validate string patterns matching TypeScript template literals
    • File Validation: Built-in File object validation with size and MIME type constraints
    • Recursive Types: Full support for recursive and self-referential schemas
    • JSON Schema: First-party JSON Schema generation
    • Function Validation: Type-safe function definitions with validated inputs/outputs
    Recommended Servers
    vastlint - IAB XML VAST validator and linter
    vastlint - IAB XML VAST validator and linter
    InstantDB
    InstantDB
    Prisma
    Prisma
    Repository
    slanycukr/riot-api-project
    Files