Basics of Zod

What is Zod?

Zod is a TypeScript-first schema validation library.

You define what data should look like:

import { z } from "zod";

const User = z.object({
  name: z.string(),
  age: z.number(),
});

Then validate data:

const result = User.safeParse(data);

Basic Types

z.string();
z.number();
z.boolean();
z.bigint();
z.date();
z.undefined();
z.null();

Example:

const name = z.string();

name.parse("Marvin"); // "Marvin"
name.parse(123); // throws

Objects

const User = z.object({
  username: z.string(),
  age: z.number(),
  active: z.boolean(),
});
User.parse({
  username: "marvin",
  age: 25,
  active: true,
});

Optional Fields

const User = z.object({
  username: z.string(),
  bio: z.string().optional(),
});

bio can be missing.


Nullable Fields

const User = z.object({
  bio: z.string().nullable(),
});

bio must exist, but can be null.


Arrays

const Tags = z.array(z.string());
Tags.parse(["js", "typescript", "zod"]);

Enums

const Role = z.enum(["user", "admin"]);
Role.parse("admin"); // "admin"

Constraints

const Password = z.string().min(8).max(100);
const Age = z.number().int().min(18).max(120);

Parsing

parse()

Throws if invalid:

const user = User.parse(data);

Good when invalid input should immediately become an exception.

safeParse()

Doesn’t throw:

const result = User.safeParse(data);

if (!result.success) {
  console.log(result.error);
} else {
  console.log(result.data);
}

Useful for HTTP request validation.


Transform

You can transform validated data:

const Email = z
  .string()
  .email()
  .transform((email) => email.toLowerCase());
Email.parse("USER@EXAMPLE.COM");
// "user@example.com"

Infer TypeScript Types

Zod can generate a TypeScript type from a schema:

const User = z.object({
  name: z.string(),
  age: z.number(),
});

type User = z.infer<typeof User>;

Equivalent to:

type User = {
  name: string;
  age: number;
};

Schema = runtime validation

z.infer = compile-time type


Common HTTP Pattern

For a POST endpoint:

const Signup = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

const result = Signup.safeParse(await c.req.json());

if (!result.success) {
  return c.json({ error: "Invalid input" }, 400);
}

const data = result.data;

Now data is validated.


Useful Methods

.optional()
.nullable()
.array()
.min()
.max()
.length()
.email()
.url()
.uuid()
.int()
.regex()
.refine()
.transform()

Mental Model

Untrusted data

    Zod

validated data

   application

For web applications:

HTTP request

JSON

Zod schema

validation

database / business logic

Main rule: validate data at the boundary before trusting it.