Lesson 6: Real-World Schema
"$defs" lets you define reusable sub-schemas in one place, avoiding repetition when the same shape appears in multiple parts of your schema. The "$ref" keyword references one of those definitions using a JSON Pointer like "#/$defs/Address". This composability is essential when building schemas for real-world API responses that share common structures such as address, line items, or user profiles. Putting it all together produces a self-documenting schema that is easy to maintain as your data model evolves.
Why This Matters
Production APIs rarely have one flat shape — an order response reuses the same Address shape for shipping and billing, a User object shows up in dozens of endpoints, and a Money type needs the same currency+amount validation everywhere. Without $defs and $ref, teams end up copy-pasting the same nested schema in ten places, and when the shape changes (adding a "country" field, say), nine of those copies quietly go stale. $defs/$ref keep a single definition as the source of truth, and this same pattern is exactly how OpenAPI's "components/schemas" and generated SDK types work — learning it here transfers directly to designing real API contracts.
Common Mistakes
- ✕ Assuming "$ref" can point straight to another file without any setup.A bare "$ref": "./address.schema.json" requires the validator to resolve external files (or a base URI), which many simple validators — including browser-based playgrounds — don't support. Internal references like "#/$defs/Address" always work because they resolve within the same document.
- ✕ Defining a shape in "$defs" and forgetting to actually reference it anywhere.An unused entry under $defs validates nothing on its own — it's just a dictionary of reusable pieces. Only properties that use $ref to point at it get validated against that shape.
- ✕ Copy-pasting the same nested object schema in multiple places instead of extracting it to $defs.Duplication drifts: when the Address shape needs a new field, every inline copy has to be updated by hand. Extract anything reused more than once into $defs and reference it with $ref.
- ✕ Mixing up Draft-07's "definitions" keyword with Draft 2020-12's "$defs".Older schemas use "definitions" and reference it as "#/definitions/Address". Draft 2020-12 renamed it to "$defs" ("#/$defs/Address") — both work only if the $ref path matches the keyword actually used in that document.
Challenge
Add a billingAddress field (same shape as shippingAddress) using $ref: '#/$defs/Address'.