Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    prowler-cloud

    zod-4

    prowler-cloud/zod-4
    Coding
    12,952
    3 installs

    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

    Zod 4 schema validation patterns. Trigger: When creating or updating Zod v4 schemas for validation/parsing (forms, request payloads, adapters), including v3 -> v4 migration patterns.

    SKILL.md

    Breaking Changes from Zod 3

    // ❌ Zod 3 (OLD)
    z.string().email()
    z.string().uuid()
    z.string().url()
    z.string().nonempty()
    z.object({ name: z.string() }).required_error("Required")
    
    // ✅ Zod 4 (NEW)
    z.email()
    z.uuid()
    z.url()
    z.string().min(1)
    z.object({ name: z.string() }, { error: "Required" })
    

    Basic Schemas

    import { z } from "zod";
    
    // Primitives
    const stringSchema = z.string();
    const numberSchema = z.number();
    const booleanSchema = z.boolean();
    const dateSchema = z.date();
    
    // Top-level validators (Zod 4)
    const emailSchema = z.email();
    const uuidSchema = z.uuid();
    const urlSchema = z.url();
    
    // With constraints
    const nameSchema = z.string().min(1).max(100);
    const ageSchema = z.number().int().positive().max(150);
    const priceSchema = z.number().min(0).multipleOf(0.01);
    

    Object Schemas

    const userSchema = z.object({
      id: z.uuid(),
      email: z.email({ error: "Invalid email address" }),
      name: z.string().min(1, { error: "Name is required" }),
      age: z.number().int().positive().optional(),
      role: z.enum(["admin", "user", "guest"]),
      metadata: z.record(z.string(), z.unknown()).optional(),
    });
    
    type User = z.infer<typeof userSchema>;
    
    // Parsing
    const user = userSchema.parse(data);  // Throws on error
    const result = userSchema.safeParse(data);  // Returns { success, data/error }
    
    if (result.success) {
      console.log(result.data);
    } else {
      console.log(result.error.issues);
    }
    

    Arrays and Records

    // Arrays
    const tagsSchema = z.array(z.string()).min(1).max(10);
    const numbersSchema = z.array(z.number()).nonempty();
    
    // Records (objects with dynamic keys)
    const scoresSchema = z.record(z.string(), z.number());
    // { [key: string]: number }
    
    // Tuples
    const coordinatesSchema = z.tuple([z.number(), z.number()]);
    // [number, number]
    

    Unions and Discriminated Unions

    // Simple union
    const stringOrNumber = z.union([z.string(), z.number()]);
    
    // Discriminated union (more efficient)
    const resultSchema = z.discriminatedUnion("status", [
      z.object({ status: z.literal("success"), data: z.unknown() }),
      z.object({ status: z.literal("error"), error: z.string() }),
    ]);
    

    Transformations

    // Transform during parsing
    const lowercaseEmail = z.email().transform(email => email.toLowerCase());
    
    // Coercion (convert types)
    const numberFromString = z.coerce.number();  // "42" → 42
    const dateFromString = z.coerce.date();      // "2024-01-01" → Date
    
    // Preprocessing
    const trimmedString = z.preprocess(
      val => typeof val === "string" ? val.trim() : val,
      z.string()
    );
    

    Refinements

    const passwordSchema = z.string()
      .min(8)
      .refine(val => /[A-Z]/.test(val), {
        message: "Must contain uppercase letter",
      })
      .refine(val => /[0-9]/.test(val), {
        message: "Must contain number",
      });
    
    // With superRefine for multiple errors
    const formSchema = z.object({
      password: z.string(),
      confirmPassword: z.string(),
    }).superRefine((data, ctx) => {
      if (data.password !== data.confirmPassword) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: "Passwords don't match",
          path: ["confirmPassword"],
        });
      }
    });
    

    Optional and Nullable

    // Optional (T | undefined)
    z.string().optional()
    
    // Nullable (T | null)
    z.string().nullable()
    
    // Both (T | null | undefined)
    z.string().nullish()
    
    // Default values
    z.string().default("unknown")
    z.number().default(() => Math.random())
    

    Error Handling

    // Zod 4: Use 'error' param instead of 'message'
    const schema = z.object({
      name: z.string({ error: "Name must be a string" }),
      email: z.email({ error: "Invalid email format" }),
      age: z.number().min(18, { error: "Must be 18 or older" }),
    });
    
    // Custom error map
    const customSchema = z.string({
      error: (issue) => {
        if (issue.code === "too_small") {
          return "String is too short";
        }
        return "Invalid string";
      },
    });
    

    React Hook Form Integration

    import { useForm } from "react-hook-form";
    import { zodResolver } from "@hookform/resolvers/zod";
    
    const schema = z.object({
      email: z.email(),
      password: z.string().min(8),
    });
    
    type FormData = z.infer<typeof schema>;
    
    function Form() {
      const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
        resolver: zodResolver(schema),
      });
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          <input {...register("email")} />
          {errors.email && <span>{errors.email.message}</span>}
        </form>
      );
    }
    
    Recommended Servers
    vastlint - IAB XML VAST validator and linter
    vastlint - IAB XML VAST validator and linter
    Vercel Grep
    Vercel Grep
    InstantDB
    InstantDB
    Repository
    prowler-cloud/prowler
    Files