Overview of 2019-09
JSON Schema 2019-09 (informally "draft-08") is a major revision that introduced structural changes later refined in 2020-12. It was the first draft to introduce vocabularies — a mechanism for declaring which keyword sets a schema uses — though the vocabulary system was not yet mandatory in 2019-09 and was fully activated in 2020-12.
The draft also renamed several keywords to align with URI terminology, added important new keywords for controlling unknown properties, and significantly reworked how $ref interacts with other keywords in the same schema object.
Formal Vocabulary System (Preview)
2019-09 introduced the $vocabulary keyword and the concept of separating JSON Schema keywords into named vocabularies. The vocabularies defined were similar to those later finalised in 2020-12, but their use in 2019-09 meta-schemas was optional.
This was intentional — the working group wanted to pilot the vocabulary concept with 2019-09 while gathering implementor feedback before making it mandatory. The result was that most 2019-09 validators treated the vocabulary system as advisory, leading to continued variation in how custom vocabularies were handled. 2020-12 addressed this.
unevaluatedProperties and unevaluatedItems
The most impactful new keywords in 2019-09 are unevaluatedProperties and unevaluatedItems. They solve a long-standing limitation of additionalProperties: the inability to work correctly alongside allOf, anyOf, or $ref.
additionalProperties only knows about properties defined in the same schema object. If an allOf branch defines a property, additionalProperties in the parent doesn't see it and wrongly rejects it. unevaluatedProperties is annotation-aware: it collects the set of all properties that have been successfully validated by any keyword in the entire schema tree, and applies its constraint only to the remainder. This makes strict closed-world object validation possible in combination with schema composition.
$ref and $id Changes
In draft-07 and earlier, a schema object containing $ref ignored any sibling keywords — the ref was a complete replacement. 2019-09 lifted this restriction: sibling keywords alongside $ref are now evaluated alongside the referenced schema. This enables patterns like:
{
"$ref": "#/$defs/Base",
"title": "Extended Model",
"description": "Extends Base with title annotation"
}The $id keyword was also tightened: it must be an absolute or relative URI reference, and its scope resolution rules were specified more precisely to avoid ambiguity in nested schemas.