Specification scope: Core with the Validation and Conditional Composition companion specifications.

A German address and a Canadian address need different postal-code checks. Both still have the same structural type. The country selects an additional validation rule for postalCode.

Conditional composition evaluates overlays against the current JSON node. It leaves the data’s representation alone: no new choice, no derived type.

One address, conditional policy

The object below always has the same four properties. The condition examines country; the selected branch adds the corresponding pattern constraint to postalCode.

{
  "$schema": "https://json-structure.org/meta/validation/v0/#",
  "$id": "https://schemas.example.com/postal-address-policy",
  "name": "PostalAddress",
  "type": "object",
  "properties": {
    "street": { "type": "string" },
    "city": { "type": "string" },
    "country": { "type": "string" },
    "postalCode": { "type": "string" }
  },
  "required": ["street", "city", "country", "postalCode"],
  "additionalProperties": false,
  "if": {
    "properties": {
      "country": { "type": "string", "const": "DE" }
    },
    "required": ["country"]
  },
  "then": {
    "properties": {
      "postalCode": { "type": "string", "pattern": "^[0-9]{5}$" }
    }
  },
  "else": {
    "if": {
      "properties": {
        "country": { "type": "string", "const": "CA" }
      },
      "required": ["country"]
    },
    "then": {
      "properties": {
        "postalCode": {
          "type": "string",
          "pattern": "^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$"
        }
      }
    }
  }
}

This Canadian instance keeps the ordinary address shape:

{
  "street": "111 Wellington Street",
  "city": "Ottawa",
  "country": "CA",
  "postalCode": "K1A 0A9"
}

The engine first evaluates the complete object against the base schema. It then evaluates the if schema against that same object. Since country is not DE, the outer else applies. Its nested condition matches CA, so the Canadian postal-code overlay must also match.

For another country, neither then branch applies. postalCode remains a required string, but this schema imposes no country-specific pattern.

A branch adds constraints

The base properties and required constraints remain in force after a branch is selected. The branch adds constraints to the current node, and all of them must hold.

That is why the branches mention only the policy delta. Repeating the full address schema in each branch would invite drift and suggest separate types where none exist.

The required inside each if is deliberate. Without it, a condition that only constrains country may succeed vacuously when the property is absent. The base schema already requires country, but keeping the condition complete makes its matching rule explicit and reusable.

Use a core choice when alternatives have different representations or structures selected by a discriminator. Use conditional composition when one stable type carries policies that depend on its values or property presence.

Where the draft and meta-schema differ

The conditional-composition draft calls its feature JSONSchemaConditionalComposition; the extended meta-schema offers JSONStructureConditionalComposition. The validation meta-schema enables the repository spelling by default, so the example needs no explicit $uses entry.

Core defines const, and the validation add-in defines pattern. As checked on 25 August 2026, the CompositionObjectAddIn in meta/extended/v0/index.json does not admit the no-type object schemas used for these branches. The JSON is syntactically valid and follows the draft’s evaluation model. Meta-schema validation can therefore fail before it examines an address instance.