Skip to Content
GuidesSchema Development

Schema Development Guide

For: Developers designing JSON schemas
Level: Intermediate
Time to read: 25 minutes
Examples: 12+ complete schemas

This guide shows how to design, evolve, and test JSON schemas used in Cascade workflows for forms, validation, and UI rendering.


JSON Schema Fundamentals

Minimal Schema

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "title": "Contact", "properties": { "name": { "type": "string", "title": "Full Name" }, "email": { "type": "string", "title": "Email", "format": "email" } }, "required": ["name", "email"], "additionalProperties": false }

Schema Structure

$schema - JSON Schema version (always draft-07) type - Data type (object, string, number, etc) title - Human-readable name properties - Object field definitions required - Mandatory fields additionalProperties - Allow/disallow extra fields

Schema Design Patterns

Pattern 1: Text & Number Inputs

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "full_name": { "type": "string", "title": "Full Name", "minLength": 1, "maxLength": 100 }, "age": { "type": "integer", "title": "Age", "minimum": 0, "maximum": 150 }, "salary": { "type": "number", "title": "Annual Salary", "minimum": 0, "multipleOf": 100 // Must be multiple of 100 }, "bio": { "type": "string", "title": "Biography", "minLength": 10, "maxLength": 1000, "x-ui-type": "textarea", "x-ui-rows": 5 } } }

Pattern 2: Enums & Dropdowns

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "department": { "type": "string", "title": "Department", "enum": ["engineering", "sales", "marketing", "hr"], "default": "engineering" }, "access_level": { "type": "string", "title": "Access Level", "enum": ["viewer", "editor", "admin"], "x-ui-type": "select" }, "languages": { "type": "array", "items": { "type": "string", "enum": ["english", "spanish", "french", "german"] }, "title": "Languages", "x-ui-type": "multi-select" } } }

Pattern 3: Nested Objects

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "applicant": { "type": "object", "title": "Applicant Information", "properties": { "first_name": {"type": "string"}, "last_name": {"type": "string"}, "date_of_birth": {"type": "string", "format": "date"} }, "required": ["first_name", "last_name"] }, "address": { "type": "object", "title": "Address", "properties": { "street": {"type": "string"}, "city": {"type": "string"}, "state": {"type": "string"}, "zip": {"type": "string", "pattern": "^[0-9]{5}$"} }, "required": ["street", "city", "state", "zip"] } } }

Pattern 4: Arrays & Collections

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "items": { "type": "array", "title": "Order Items", "items": { "type": "object", "properties": { "sku": {"type": "string"}, "quantity": {"type": "integer", "minimum": 1}, "price": {"type": "number"} }, "required": ["sku", "quantity", "price"] }, "minItems": 1, "maxItems": 100 }, "tags": { "type": "array", "items": {"type": "string"}, "title": "Tags", "x-ui-type": "tag-input" } } }

Pattern 5: Conditional Fields

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "employment_type": { "type": "string", "title": "Employment Type", "enum": ["w2", "contractor", "freelance"] }, "ssn": { "type": "string", "title": "SSN (W2 only)", "pattern": "^[0-9]{3}-[0-9]{2}-[0-9]{4}$", "x-ui-visible-if": "{{ form.employment_type === 'w2' }}" }, "tax_id": { "type": "string", "title": "Tax ID", "x-ui-visible-if": "{{ form.employment_type === 'contractor' }}" } }, "required": ["employment_type"] }

Real-World Example: Loan Application Evolution

V1.0 - Initial Schema (Simple)

{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Loan Application", "type": "object", "properties": { "applicant_name": {"type": "string"}, "email": {"type": "string", "format": "email"}, "phone": {"type": "string"}, "annual_income": {"type": "number"}, "amount_requested": {"type": "number"} }, "required": ["applicant_name", "email", "annual_income", "amount_requested"] }

V2.0 - Enhanced Schema (Backward Compatible)

{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Loan Application", "type": "object", "properties": { "applicant_name": {"type": "string"}, "email": {"type": "string", "format": "email"}, "phone": {"type": "string"}, "annual_income": {"type": "number"}, "amount_requested": {"type": "number"}, // NEW: Additional fields "credit_score": { "type": "integer", "title": "Credit Score (optional)" }, "employment_status": { "type": "string", "enum": ["employed", "self_employed", "retired"] }, "existing_debts": { "type": "number", "title": "Existing Monthly Debts" } }, "required": ["applicant_name", "email", "annual_income", "amount_requested"] // V1 fields still required, new fields optional }

V3.0 - Structured Schema (Backward Compatible)

{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Loan Application", "type": "object", "properties": { "applicant": { "type": "object", "title": "Applicant Information", "properties": { "name": {"type": "string"}, "email": {"type": "string", "format": "email"}, "phone": {"type": "string"}, "date_of_birth": {"type": "string", "format": "date"} }, "required": ["name", "email"] }, "financial": { "type": "object", "title": "Financial Information", "properties": { "annual_income": {"type": "number"}, "existing_debts": {"type": "number"}, "credit_score": {"type": "integer"} }, "required": ["annual_income"] }, "loan": { "type": "object", "title": "Loan Details", "properties": { "amount_requested": {"type": "number"}, "purpose": { "type": "string", "enum": ["home", "auto", "personal", "business"] }, "term_months": {"type": "integer"} }, "required": ["amount_requested"] } }, "required": ["applicant", "financial", "loan"] }

Schema Versioning Strategy

Version Numbering

MAJOR.MINOR.PATCH MAJOR - Breaking changes (v1→v2) MINOR - Backward-compatible additions PATCH - Bug fixes, no behavioral changes

Breaking Changes Examples

Breaking:

  • Removing a field (old apps send it, new schema rejects)
  • Changing field type (string → number)
  • Making optional field required
  • Renaming fields

Backward Compatible:

  • Adding optional fields
  • Adding enum values
  • Loosening constraints (minLength 5→2)
  • Grouping fields into new objects (if old fields still exist)

Evolution Pattern

# Schema versioning in URN urn:cascade:schema:loan_application # Always latest (v3) urn:cascade:schema:loan_application:v1 # Pinned version urn:cascade:schema:loan_application:v2 # Pinned version urn:cascade:schema:loan_application:v3 # Pinned version # Workflow migration # Old workflows: use v1 # New workflows: use v3 # Both work simultaneously

Schema Composition with $ref

Reusable Components

{ "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "address": { "type": "object", "properties": { "street": {"type": "string"}, "city": {"type": "string"}, "state": {"type": "string"}, "zip": {"type": "string"} }, "required": ["street", "city"] }, "contact": { "type": "object", "properties": { "email": {"type": "string", "format": "email"}, "phone": {"type": "string"} } } }, "type": "object", "properties": { "billing_address": {"$ref": "#/definitions/address"}, "shipping_address": {"$ref": "#/definitions/address"}, "contact_info": {"$ref": "#/definitions/contact"} } }

Best Practices

✅ DO:

  • Use semantic property names
  • Add descriptions for complex fields
  • Set reasonable min/max constraints
  • Use additionalProperties: false for strict validation
  • Test schema changes thoroughly
  • Document breaking changes
  • Version schemas consistently
  • Use references to avoid duplication

❌ DON’T:

  • Mix types (number AND string)
  • Create deeply nested structures (>3 levels)
  • Change field types between versions
  • Remove required fields
  • Make assumptions about data size
  • Forget about backward compatibility

Testing Schemas

Validate Schema Structure

cascade schema validate urn:cascade:schema:loan_application # Checks: JSON syntax, required properties, type consistency

Test with Sample Data

cascade schema test urn:cascade:schema:loan_application \ --input '{"applicant":{"name":"Alice","email":"alice@example.com"},...}' # Validates data against schema

Next Steps

Need to build workflows?Workflow Development Guide

Need activity help?Activity Development Guide

Want to understand UI rendering?Capabilities: UI Rendering


Updated: October 29, 2025
Version: 1.0
Examples: 12+ schemas
Patterns: 5 proven designs

Last updated on