# Zod4

> Comprehensive guide for Zod 4 schema validation library. This skill should be used when migrating from Zod 3, learning Zod 4 idioms, or building new validation schemas. Covers breaking changes, new features, and migration patterns.

- Skill: `kastalien-research/zod4` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add kastalien-research/zod4`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kastalien-research/zod4/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kastalien-research (https://skillmd.com/u/kastalien-research)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kastalien-research/zod4

---


# Zod 4 Expert Guide

Zod 4 is a major release with significant performance improvements, reduced TypeScript compilation times, and a cleaner API. This skill covers migration from v3 and idiomatic Zod 4 usage.

## Quick Migration Checklist

Before diving deep, address these high-impact breaking changes:

| Change | Zod 3 | Zod 4 |
|--------|-------|-------|
| Record schemas | `z.record(z.string())` | `z.record(z.string(), z.string())` |
| Strict objects | `.strict()` | `z.strictObject({...})` |
| Passthrough | `.passthrough()` | `z.looseObject({...})` |
| Error formatting | `err.format()` | `z.treeifyError(err)` |
| Coerce input type | `string` | `unknown` |

Install Zod 4:
```bash
npm install zod@^4.0.0
```

For detailed breaking changes, see [./reference/breaking-changes.md](./reference/breaking-changes.md).

---

## Key Breaking Changes

### 1. z.record() Requires Two Arguments

```typescript
// Zod 3 (BROKEN in v4)
z.record(z.string());

// Zod 4 (REQUIRED)
z.record(z.string(), z.string());
```

### 2. Strict/Loose Object Syntax

```typescript
// Zod 3
z.object({ name: z.string() }).strict();
z.object({ name: z.string() }).passthrough();

// Zod 4
z.strictObject({ name: z.string() });
z.looseObject({ name: z.string() });
```

### 3. .default() Behavior Changed

In Zod 4, `.default()` short-circuits if input is `undefined` and returns the default directly (without parsing). Use `.prefault()` for the old behavior:

```typescript
// Zod 4: default must match OUTPUT type
const schema = z.string()
  .transform(val => val.length)
  .default(0);  // Returns 0 directly, not parsed

// To parse the default (old behavior):
const schema = z.string()
  .transform(val => val.length)
  .prefault("tuna");  // "tuna" is parsed → 4
```

### 4. Error Handling Changes

```typescript
// Zod 3
const formatted = err.format();
const flat = err.flatten();

// Zod 4
const tree = z.treeifyError(err);

// Adding issues
err.issues.push({ /* new issue */ });
```

### 5. z.coerce Input Type

```typescript
const schema = z.coerce.string();
type Input = z.input<typeof schema>;
// Zod 3: string
// Zod 4: unknown
```

---

## New Features

### z.file() - File Validation

```typescript
const fileSchema = z.file()
  .min(10_000)        // minimum bytes
  .max(1_000_000)     // maximum bytes
  .mime(["image/png", "image/jpeg"]);
```

### z.templateLiteral() - Template Literal Types

```typescript
const css = z.templateLiteral([z.number(), z.enum(["px", "em", "rem"])]);
// `${number}px` | `${number}em` | `${number}rem`

const email = z.templateLiteral([
  z.string().min(1),
  "@",
  z.string().max(64),
]);
```

### .meta() - Schema Metadata

```typescript
z.string().meta({
  id: "email_address",
  title: "Email address",
  description: "User's email",
  examples: ["user@example.com"]
});
```

### z.globalRegistry - Global Schema Registry

```typescript
z.globalRegistry.add(mySchema, {
  id: "user_schema",
  title: "User",
  description: "User data structure"
});
```

### z.locales - Internationalization

```typescript
import { z } from "zod";
import { en } from "zod/locales/en";

z.config(z.locales.en());  // Configure error messages
```

### z.strictObject() / z.looseObject()

```typescript
// Rejects unknown keys
z.strictObject({ name: z.string() });

// Allows unknown keys (passthrough)
z.looseObject({ name: z.string() });
```

For complete new features guide, see [./reference/new-features.md](./reference/new-features.md).

---

## Zod Mini

Zod Mini (`zod/mini`) provides a smaller bundle with tree-shakable, functional API:

```typescript
import * as z from "zod/mini";

// Functional checks instead of methods
const schema = z.pipe(
  z.string(),
  z.minLength(1),
  z.maxLength(100),
  z.regex(/^[a-z]+$/)
);

// Available functions
z.lt(value);
z.gt(value);
z.positive();
z.negative();
z.minLength(value);
z.maxLength(value);
z.regex(pattern);
z.trim();
z.toLowerCase();
z.toUpperCase();
```

---

## Migration Patterns

### Pattern 1: Update z.record() Calls

Search and replace:
```typescript
// Find
z.record(valueSchema)

// Replace with
z.record(z.string(), valueSchema)
```

### Pattern 2: Update Strict Objects

```typescript
// Find
z.object({...}).strict()

// Replace with
z.strictObject({...})
```

### Pattern 3: Update Error Handling

```typescript
// Find
try {
  schema.parse(data);
} catch (err) {
  if (err instanceof z.ZodError) {
    const formatted = err.format();
  }
}

// Replace with
try {
  schema.parse(data);
} catch (err) {
  if (err instanceof z.ZodError) {
    const tree = z.treeifyError(err);
  }
}
```

### Pattern 4: Fix Default Values

If using `.default()` with transforms, check if default matches output type:

```typescript
// If this breaks:
z.string().transform(s => s.length).default("hello")

// Change to:
z.string().transform(s => s.length).prefault("hello")
// OR
z.string().transform(s => s.length).default(5)  // Match output type
```

For complete migration checklist, see [./reference/migration-checklist.md](./reference/migration-checklist.md).

---

## Common Issues

| Error | Cause | Fix |
|-------|-------|-----|
| `Expected 2 arguments, got 1` | `z.record()` single arg | Add key schema: `z.record(z.string(), ...)` |
| `Property 'strict' does not exist` | `.strict()` removed | Use `z.strictObject()` |
| `Property 'format' does not exist` | `.format()` removed | Use `z.treeifyError(err)` |
| Type mismatch on `.default()` | Default must match output | Use `.prefault()` or fix default type |

---

## Codemod

A community-maintained codemod is available:

```bash
npx zod-v3-to-v4
```

This automates many of the breaking change fixes.

---

## Resources

- [Zod 4 Documentation](https://zod.dev)
- [Migration Guide](https://zod.dev/v4)
- [Zod GitHub](https://github.com/colinhacks/zod)

