flashman
← All guides

JSON Schema conditional validation with if, then, and else

Design maintainable JSON Schema conditionals by defining presence rules, decision tables, branch composition, annotation behavior, and portable tests.

2026-09-26 · 8 min read

  • json-schema
  • validation
  • architecture

The if, then, and else keywords let a JSON Schema select constraints from instance data. The if subschema is evaluated as a condition; when it succeeds, then applies, and when it fails, else applies. The condition's own result is not an assertion against the overall instance.

Conditionals are valuable for country-specific addresses, plan-dependent settings, tagged records, and versioned payloads. They become fragile when presence, type, and value tests are mixed implicitly or when several branches overlap.

Write the rule as a decision table

Before writing schema, list the relevant input states and the constraints each state selects. Include absent, null, malformed, recognized, and unknown discriminator values. This exposes unstated defaults and prevents the happy path from defining the whole contract.

  • Name the field or shape that selects a branch.
  • State whether the selector is required.
  • Define unknown-value and missing-value behavior.
  • Give every row a positive and negative fixture.

Make presence and type explicit

A properties subschema only evaluates a property when that property exists. If the condition means type equals business, include required for type inside if. Otherwise a missing selector can make the condition succeed and unexpectedly activate then.

Constrain the selector's type and accepted values in the base schema when those rules apply to every branch. Keep branch-specific requirements in then or else so diagnostics point to the consequence that actually failed.

Choose a composition that readers can audit

Use one conditional for a genuine binary choice. For several tagged variants, compare nested conditionals with oneOf branches that each require a unique const discriminator. The best design makes exclusivity and fallback behavior visible without relying on special renderer support.

Avoid copying large object schemas into every consequence. Factor stable constraints into $defs and use controlled $ref values, while checking how sibling keywords and the selected draft behave.

Account for annotations and unevaluated properties

Modern applicators can contribute annotations that affect keywords such as unevaluatedProperties. Only the selected successful paths contribute as defined by the dialect and implementation, so an apparently equivalent rewrite can change which properties count as evaluated.

Pin the $schema URI, validator version, reference registry, and output mode. Compare final validity first and treat diagnostic wording as implementation-specific unless the application has deliberately normalized it.

Publish a branch conformance suite

Use Flashman's JSON formatter for schemas and instances, YAML/JSON converter for configuration copies, diff for validator matrices, regex tester for public pattern constraints, and Markdown editor for the decision table.

Cover absent and null selectors, wrong types, each recognized value, unknown values, failed consequences, overlapping branches, nested conditionals, $ref boundaries, unevaluated properties, annotation output, validator upgrades, and generated clients.

Try these tools