Convert Nested JSON Objects to Zod Schemas
Learn how to generate multiple Zod schema constants from a JSON object with nested sub-objects. Each nested object gets its own reusable schema.
Basic Types
Detailed Explanation
Handling Nested Structures with Zod
Real-world JSON is rarely flat. APIs typically return objects inside objects, and each level of nesting maps to a separate Zod schema constant that can be composed together.
Example JSON
{
"id": 1,
"name": "Acme Corp",
"address": {
"street": "123 Main St",
"city": "Springfield",
"geo": {
"lat": 39.7817,
"lng": -89.6501
}
}
}
Generated Zod Schema
import { z } from "zod";
const geoSchema = z.object({
lat: z.number(),
lng: z.number(),
});
const addressSchema = z.object({
street: z.string(),
city: z.string(),
geo: geoSchema,
});
const companySchema = z.object({
id: z.number().int(),
name: z.string(),
address: addressSchema,
});
type Geo = z.infer<typeof geoSchema>;
type Address = z.infer<typeof addressSchema>;
type Company = z.infer<typeof companySchema>;
Why Separate Schemas?
Extracting each nested object into its own schema provides several benefits:
- Reusability —
geoSchemacan be reused anywhere coordinates appear (e.g., store locations, event venues). - Composability — Zod schemas compose naturally. You can extend, merge, or pick fields from existing schemas.
- Testability — You can validate
addressSchemaindependently ofcompanySchema, making unit tests simpler. - Readability — Deeply nested inline schemas quickly become unreadable.
Schema Composition Methods
Zod provides powerful composition tools:
// Extend a schema
const detailedAddressSchema = addressSchema.extend({
zipCode: z.string(),
});
// Merge two schemas
const fullSchema = addressSchema.merge(contactSchema);
// Pick specific fields
const locationSchema = addressSchema.pick({ city: true, geo: true });
These composition patterns let you build complex validation from simple, tested building blocks.
Use Case
You are integrating a third-party API that returns deeply nested company data with address and geolocation sub-objects, and you need runtime validation at every level of nesting.