Zod v4 changed the import path. Projects using Zod v4 must import from "zod/v4", never from "zod" directly.
Critical Import Rule
// ✅ Correct — Zod v4
import { z } from "zod/v4";
// ❌ Wrong — imports Zod v3 API even if v4 is installed
import { z } from "zod";
This is the single most common mistake in Zod v4 codebases and causes subtle runtime issues.
Schema Patterns
import { z } from "zod/v4";
// Define schemas
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1).max(100),
role: z.enum(["admin", "editor", "viewer"]),
createdAt: z.date(),
});
// Infer TypeScript type from schema
type User = z.infer<typeof UserSchema>;
// Record requires two arguments in Zod v4
const MetadataSchema = z.record(z.string(), z.unknown());
Validator Organization
One validator file per domain: src/lib/validators/users.ts, src/lib/validators/orders.ts
Export named schemas and their inferred types together
Keep schemas close to where they are used (actions, API routes, forms)
Server Action Pattern
import { z } from "zod/v4";
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
});
export async function createUser(input: unknown) {
const parsed = CreateUserSchema.safeParse(input);
if (!parsed.success) {
return { success: false, error: parsed.error.message };
}
// Use parsed.data — fully typed
}
Common Pitfalls
z.record() requires two arguments in Zod v4: z.record(z.string(), z.unknown()) — one argument throws
z.coerce.date() parses strings to dates — useful for form inputs
Do not mix Zod v3 and v4 imports in the same project
Raw content
Copy this into your project — e.g. .instructions.md, .agent.md, or SKILL.md
## Overview
Zod v4 changed the import path. Projects using Zod v4 **must** import from `"zod/v4"`, never from `"zod"` directly.
## Critical Import Rule
```tsx
// ✅ Correct — Zod v4
import { z } from "zod/v4";
// ❌ Wrong — imports Zod v3 API even if v4 is installed
import { z } from "zod";
```
This is the single most common mistake in Zod v4 codebases and causes subtle runtime issues.
## Schema Patterns
```tsx
import { z } from "zod/v4";
// Define schemas
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1).max(100),
role: z.enum(["admin", "editor", "viewer"]),
createdAt: z.date(),
});
// Infer TypeScript type from schema
type User = z.infer<typeof UserSchema>;
// Record requires two arguments in Zod v4
const MetadataSchema = z.record(z.string(), z.unknown());
```
## Validator Organization
- One validator file per domain: `src/lib/validators/users.ts`, `src/lib/validators/orders.ts`
- Export named schemas and their inferred types together
- Keep schemas close to where they are used (actions, API routes, forms)
## Server Action Pattern
```tsx
import { z } from "zod/v4";
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
});
export async function createUser(input: unknown) {
const parsed = CreateUserSchema.safeParse(input);
if (!parsed.success) {
return { success: false, error: parsed.error.message };
}
// Use parsed.data — fully typed
}
```
## Common Pitfalls
- `z.record()` requires two arguments in Zod v4: `z.record(z.string(), z.unknown())` — one argument throws
- `z.coerce.date()` parses strings to dates — useful for form inputs
- Do not mix Zod v3 and v4 imports in the same project