Nested Object Validation in JSON Schema
Validate deeply nested JSON objects with JSON Schema. Learn to define hierarchical structures, nested required fields, and multi-level object composition.
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1 },
"age": { "type": "integer", "minimum": 0 }
},
"required": ["name"]
},
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" },
"postalCode": { "type": "string" },
"coordinates": {
"type": "object",
"properties": {
"latitude": { "type": "number", "minimum": -90, "maximum": 90 },
"longitude": { "type": "number", "minimum": -180, "maximum": 180 }
},
"required": ["latitude", "longitude"]
}
},
"required": ["street", "city", "country"]
}
},
"required": ["user", "address"]
}Test Data
{
"user": {
"name": "Alice Chen",
"age": 32
},
"address": {
"street": "123 Main Street",
"city": "San Francisco",
"country": "US",
"postalCode": "94102",
"coordinates": {
"latitude": 37.7749,
"longitude": -122.4194
}
}
}Detailed Explanation
Nested Object Validation
Real-world JSON data is rarely flat — it contains objects within objects. JSON Schema handles nested structures naturally by defining sub-schemas for each level of nesting.
Basic Nesting
{
"type": "object",
"properties": {
"address": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
}
The inner schema validates address as an object with a required city string property. Each nesting level has its own independent properties, required, and other keywords.
How the Example Schema Works
The schema defines a two-level nested structure with an optional third level:
Level 1 — the root object requires both user and address.
Level 2 — user is an object with a required name and an optional age. The address object requires street, city, and country, with optional postalCode and coordinates.
Level 3 — coordinates is an object nested inside address, with required latitude (range -90 to 90) and longitude (range -180 to 180).
The test data passes all three levels: the user has a name, the address has all required fields, and the coordinates are valid geographic values.
Required at Each Level
A critical point: each object has its own required array. The root-level required: ["user", "address"] does not make user.name required — that is controlled by the required inside the user sub-schema.
Avoiding Deep Nesting with $ref
When schemas get deeply nested, readability suffers. Use $ref with $defs to flatten the structure:
{
"type": "object",
"properties": {
"address": { "$ref": "#/$defs/Address" }
},
"$defs": {
"Address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"coordinates": { "$ref": "#/$defs/GeoPoint" }
}
},
"GeoPoint": {
"type": "object",
"properties": {
"latitude": { "type": "number" },
"longitude": { "type": "number" }
}
}
}
}
This approach keeps each definition at the top level, making schemas easier to read, test, and reuse. See the ref-definitions example for a deep dive into $ref.
Error Path Reporting
When validation fails in a nested structure, good validators report the JSON Pointer path to the error (e.g., /address/coordinates/latitude). This makes debugging deeply nested structures straightforward.
Use Case
Use nested object schemas for API endpoints that accept structured data like user profiles with addresses, orders with line items, or configuration objects with grouped settings. Nested validation ensures every level of your data hierarchy is correct before processing.