How to convert JSON to Zod and validate API data
Generate Zod schemas from a JSON, validate API responses at runtime, and refine the schema with email, optional and nullable values.
Published on
Types don't validate anything at runtime
TypeScript interfaces disappear once the code is compiled. If an API starts returning a field in a different shape, or stops sending a field, your application only finds out when it breaks. Zod fixes that: you describe the expected shape in a schema, and it checks the real data as it arrives.
Writing schemas by hand for large responses is tedious. Converting a sample JSON into a Zod schema gives you the structure ready to refine.
Step by step
- Open Transform and choose JSON → Zod.
- Paste a JSON representative of the response you want to validate.
- Adjust the Root name (here,
User) and click Transform. - Install the library with
npm install zod, importz, and paste in the generated schemas.
Example
The tool's real input and output:
{
"id": 1,
"name": "Ana Souza",
"email": "ana@example.com",
"active": true,
"tags": ["admin", "beta"],
"address": { "city": "São Paulo", "zip": "01310-100" }
}const addressSchema = z.object({
city: z.string(),
zip: z.string(),
});
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string(),
active: z.boolean(),
tags: z.array(z.string()),
address: addressSchema,
});Nested objects become separate schemas (addressSchema) that the main schema reuses, which keeps the code organized and easy to reuse.
Validating the API response
import { z } from "zod";
// ... schemas generated by the tool ...
// The TypeScript type comes straight from the schema, no interface to write by hand.
type User = z.infer<typeof userSchema>;
const response = await fetch("/api/users/1");
const result = userSchema.safeParse(await response.json());
if (!result.success) {
console.error("Response doesn't match the expected shape:", result.error.issues);
} else {
console.log(result.data.name); // the data has already been validated here
}Prefer safeParse when you want to handle the error without throwing: it returns an object with success and, on failure, the list of problems found and which field they're in.
Refining the schema
The tool infers basic types from the example: text becomes z.string(), numbers become z.number(), and so on. More specific rules are up to you:
const userSchema = z.object({
id: z.number().int().positive(),
name: z.string().min(1),
email: z.string().email(),
active: z.boolean(),
tags: z.array(z.string()),
nickname: z.string().optional(), // may be missing from the response
lastLogin: z.string().nullable(), // may come back as null
});Fields that only sometimes appear
An example doesn't show which fields are optional. Compare it against the API's documentation and use.optional() and .nullable() where it makes sense.Already have the interfaces? Convert straight from TypeScript
If you already wrote the types, use the TypeScript → Zod conversion: paste the interface and get the equivalent schema back, without going through a sample JSON. Unlike inferring from JSON, here the tool sees what the types actually say, so it preserves optional fields, nullable values and literal-value unions:
type Role = "admin" | "user";
interface User {
id: number;
name: string;
email?: string;
role: Role;
nickname: string | null;
}const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().optional(),
role: z.enum(["admin", "user"]),
nickname: z.string().nullable(),
});email?: stringbecame.optional()."admin" | "user"becamez.enum([...]), even going through theRolealias.string | nullbecame.nullable().
More advanced types (generics, Partial, Record, tuples, intersections with &, and the Date type) still come out simplified as z.unknown(); review the result in those cases.
When to use just types, and when to use Zod
- Just types: for data that originates inside your own application and that you control.
- Zod: at every boundary with the outside world, like API responses, forms, uploaded files, environment variables, and localStorage content.
Frequently asked questions
Do I need to install Zod?
Yes. The generated code uses the Zod library, which you install with npm install zod. The tool only generates the schemas; importing z is on you.
Does Zod replace TypeScript interfaces?
In practice, yes. With z.infer you get the TypeScript type straight from the schema, so you keep a single definition instead of two.
What's the difference between Zod and JSON Schema?
Zod is a validation library for TypeScript. JSON Schema is a language-independent standard, useful for documentation and for sharing contracts with other systems. Transform also converts JSON into JSON Schema.
Is the generated schema final?
It's a starting point. It describes the shape of the example you pasted, with basic types. Rules like email format, minimum values, optional and nullable fields are yours to add afterward.