codez.guru

Why Share Schemas?

Imagine this:

  • Your backend validates request bodies before saving to the database
  • Your frontend validates user input before sending requests
  • Both use the same logic β€” but you’ve written it twice 😰

With Zod, you can define a schema once, then reuse it across:

  • API endpoints
  • Forms and inputs
  • TypeScript types
  • Testing

> One schema to rule them all.


Project Structure for Shared Schemas

In a monorepo or fullstack project, organize your shared logic like this:

/packages
  /schemas
    user.ts
/frontend
/backend

Or in a single repo:

/src
  /schemas
    user.ts
  /frontend
  /backend

Your schema files become single sources of truth.


Defining Schemas Once, Using Everywhere

Let’s define a reusable user schema:

// src/schemas/user.ts
import { z } from "zod";

export const RegisterSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
  password: z.string().min(6),
});

export type RegisterInput = z.infer<typeof registerschema>;

Then in your backend route:

// backend/api/register.ts
import { RegisterSchema } from "@/schemas/user";

const body = await req.json();
const result = RegisterSchema.safeParse(body);

And in your frontend form:

// frontend/forms/RegisterForm.ts
import { RegisterSchema } from "@/schemas/user";

RegisterSchema.parse(formData); // Client-side check

Example: User Registration

Shared schema file:

// schemas/user.ts
export const UserLoginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(6),
});

export type UserLoginData = z.infer<typeof userloginschema>;

Backend:

const data = await req.json();
const result = UserLoginSchema.safeParse(data);

Frontend:

const errors = validateForm(formState, UserLoginSchema);

Now both sides stay in sync β€” no drift, no surprises.


Tips for Schema Versioning

  • βœ… Tag your schemas with comments (or filenames) when API versions change
  • βœ… Avoid breaking schema changes without tracking them in version control
  • βœ… Use extend(), pick(), and omit() to adapt base schemas safely

Summary

  • Use Zod to centralize validation logic and types
  • Structure your project to share schemas across layers
  • Infer types from schemas instead of duplicating interfaces
  • Simplify testing, reduce bugs, and save time

You’ve reached the end of the Advanced Guide to Zod!

Up next: the final section β€” Practical Examples, Problems, and Real-World Solutions.


Master the Code, Be the Guru!