Schema Extensibility
also known as Reserved Fields, Namespaced Extensions
Build schemas that evolve without breaking old clients via reserved namespaces and extension blocks.
Context
A team owns a data format that lives for years and is read by clients of different ages — exported files, API payloads, event records in a queue. New fields show up regularly because the product evolves, and the team cannot reasonably upgrade every client at the same moment a new field is added. They need a way to add fields, and to let vendors add their own extensions, without forcing a coordinated release.
Problem
A rigid schema that lists exactly which fields are allowed will reject any payload that contains a new field, which means every addition becomes a breaking change for every existing client. The obvious workaround — accepting anything and validating nothing — turns the schema into mush, lets typos through, and makes it impossible to tell deliberate extensions apart from accidents. The team has to choose between cascading breaking changes and losing the schema's value as a contract, and neither is acceptable for a long-lived format.
Forces
- Old clients should ignore new fields, not error.
- New fields should be discoverable, not hidden.
- Versioning policy must be agreed upfront.
Example
A typed event stream between agent and client ships v1; six months later the client team needs three new fields and a vendor-specific extension. Without extensibility the schema breaks every old client. The team had used a versioned envelope (`{schema_version, type, payload, extensions}`) with reserved `x-vendor.*` namespaces from day one; adding the new fields and extensions ships without breaking older clients, and a `schema_version` bump is reserved for genuine incompatibilities.
Diagram
Solution
Therefore:
Define a versioned envelope (`{schema_version, type, payload}`). Reserve namespaces for extensions (`x-vendor.foo`, `extensions: {...}`). Old clients ignore unknown extensions. Bumps to schema_version are the only breaking-change signal.
What this pattern forbids. Clients cannot rely on extension fields outside their declared namespace.
And the patterns that stand alongside it, or against it —
- complementsPolymorphic Record★★— Represent a family of related entities in a single core schema with type-specific extensions.
- complementsTranslation Layer★★— Insert a typed boundary between the agent's clean domain model and a messy or legacy external API.
Neighbourhood
Click any neighbour to follow the language. Scroll to zoom, drag to pan.