Build apps with Zod
Zod provides runtime type validation for forms, API responses, and generated data structures throughout every Goodspeed app. Goodspeed generates Zod as a standard part of every app, so the output is a working codebase from day one, not a scaffold you have to finish yourself.
WHAT GETS GENERATED
Built into every Zod build
Every app Goodspeed generates with Zod includes these production-ready patterns, wired together from the first build.
| Item | Description | Strength |
|---|---|---|
| lib/validation.ts common schemas | emailSchema, passwordSchema, displayNameSchema, and feedbackSchema export reusable Zod validators. The DevAgent adds app-specific schemas for every form in the generated app. | Schemas |
| validate() typed helper | A generic validate<T>(schema, data) helper returns { success: true; data: T } or { success: false; errors: Record<string, string> }, so no try/catch at call sites. | API |
| react-hook-form integration via zodV4Resolver | lib/forms.ts includes a zodV4Resolver wrapper compatible with @hookform/resolvers that normalizes Zod v4 issues to the shape RHF expects. | Forms |
| Supabase response validation | Edge Function responses and Supabase RPC calls are parsed through Zod schemas before the data reaches the component, catching malformed responses before they crash the UI. | API Safety |
Source: gas-template repository · Schema Validation
REAL GENERATED CODE
A snippet from a Zod app the studio shipped
This pattern comes directly from the gas-template codebase, the foundation every Goodspeed app is generated on. The studio generates Zod code like this for every app in the pipeline, not just a hello-world scaffold.
validate helper
// lib/validation.ts: typed validation helper type ValidationResult<T> = | { success: true; data: T } | { success: false; errors: Record<string, string> }; export function validate<T>( schema: ZodSchema<T>, data: unknown ): ValidationResult<T> { const result = schema.safeParse(data); if (result.success) return { success: true, data: result.data }; const errors: Record<string, string> = {}; result.error.issues.forEach((e) => { const key = e.path.join('.') || 'root'; errors[key] = e.message; }); return { success: false, errors }; }
GDaily Allergens
Today's log
Gluten
Tree nuts
Shellfish
Dairy
HomeScanLogProfile