Zod Validation
> **Skill Purpose:** TypeScript-first schema validation and runtime type checking patterns
SKILL.md
Full skill instructions
Zod Validation
Skill Purpose: TypeScript-first schema validation and runtime type checking patterns
Core Skill Pattern
Objective: Establish type-safe data validation with runtime checking, TypeScript inference, and integration patterns for data integrity.
Universal Pattern:
- Define validation schemas with type inference
- Create validation patterns for different data contexts
- Set up error handling and validation reporting
- Establish integration patterns with data sources
- Create schema organization and maintenance procedures
Key Decisions (Project-Specific):
- Validation strictness and error handling approach
- Schema organization and naming conventions
- Integration depth with data sources and APIs
- Form validation vs API validation patterns
- Error reporting and user feedback mechanisms
Project-Specific Implementation Notes
Customize per project:
- Validation strictness based on data sensitivity and user experience
- Schema organization based on project complexity and team size
- Integration level based on data sources and API requirements
- Error handling based on user interface needs
- Form vs API validation separation based on architecture
Example Implementation (Zod with TypeScript Pattern)
Note: This is an example pattern using Zod. Adapt validation library and configuration based on your specific project requirements and type system needs.
Prerequisites (Example)
- Project initialized with TypeScript
- Validation requirements defined
- Data sources and API contracts established
Example: Zod Validation Implementation
Framework-Specific Example: This demonstrates the pattern using Zod with TypeScript. Adapt for your validation library and type system.
1. Basic Schema Definition
import { z } from 'zod';
// Define schema
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1).max(100),
role: z.enum(['admin', 'user', 'guest']),
createdAt: z.date(),
});
// Infer TypeScript type
type User = z.infer<typeof UserSchema>;
2. Validation
// Parse (throws on error)
const user = UserSchema.parse(untrustedData);
// Safe parse (returns result object)
const result = UserSchema.safeParse(untrustedData);
if (result.success) {
console.log(result.data);
} else {
console.log(result.error.issues);
}
3. API Request Validation
// Request body schema
const CreateUserRequestSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
password: z.string().min(8),
});
// In API route
export async function POST(request: Request) {
const body = await request.json();
const result = CreateUserRequestSchema.safeParse(body);
if (!result.success) {
return Response.json({ error: result.error.issues }, { status: 400 });
}
// result.data is typed and validated
const { email, name, password } = result.data;
}
4. Form Validation (with react-hook-form)
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
const FormSchema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Password must be at least 8 characters'),
});
function MyForm() {
const form = useForm({
resolver: zodResolver(FormSchema),
});
}
5. Database Type Alignment
// Align Zod schema with Supabase types
import { Database } from '@/types/database';
type DbUser = Database['public']['Tables']['users']['Row'];
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
// ... match database columns
}) satisfies z.ZodType<DbUser>;
File Organization
/lib/validations/
├── index.ts # Re-exports all schemas
├── user.ts # User-related schemas
├── auth.ts # Auth-related schemas
└── [feature].ts # Feature-specific schemas
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Schema | [Entity]Schema | UserSchema |
| Request | [Action][Entity]RequestSchema | CreateUserRequestSchema |
| Response | [Action][Entity]ResponseSchema | GetUserResponseSchema |
| Form | [Form]FormSchema | LoginFormSchema |
Best Practices
- Co-locate schemas with usage - Keep validation schemas near the code that uses them
- Use safeParse for user input - Never trust external data
- Align with database types - Ensure Zod schemas match Supabase types
- Provide meaningful error messages - Use
.message()for custom errors - Compose schemas - Use
.extend(),.pick(),.omit()for DRY schemas
Integration with Supabase
// Validate before insert
const validated = UserSchema.parse(userData);
const { data, error } = await supabase
.from('users')
.insert(validated);
// Validate after select
const { data } = await supabase.from('users').select('*');
const users = z.array(UserSchema).parse(data);
Stop Conditions
STOP and escalate if:
- Schema doesn't align with database types
- Validation requirements unclear
- Complex nested validation needed without clear spec
Skill Version: 1.0.0
