Skip to main content

Schema Versioning and Management

Last Updated: September 10, 2025

This document outlines the process for modifying and versioning JSON schemas in this repository. Following these guidelines is crucial for maintaining stability, ensuring backward compatibility, and allowing our systems to evolve safely.

Our strategy is built on Global Versioning and the principle of Immutability for released versions.

Quick Start

Installation

# Install schema tooling
npm install

# Generate all platform types
npm run codegen

Available Commands

CommandDescription
npm run codegenGenerate types for all platforms
npm run codegen:tsGenerate TypeScript types only
npm run codegen:swiftGenerate Swift models only
npm run codegen:pythonGenerate Python models only
npm run test:schemasFull CI validation suite

Developer Workflow

Core Philosophy

  1. Released Versions are Immutable: Once a version (e.g., v1) is in production use, its schemas must not be changed in a backward-incompatible way.
  2. Versioning is Global: A version number (v1, v2, etc.) applies to the entire system as a cohesive unit. A breaking change in any schema contributes to the next global version.
  3. We Use a Fallback System: Our application code is designed to resolve schemas by first looking for the requested version (e.g., v2) and falling back to the previous version (v1) if it's not found. This allows us to only copy files that have actually changed.

Folder Structure

Our schemas are organized by their domain and then by version:

src/
├── layers/
│ └── v1/
│ └── image.json
│ └── v2/
│ └── image.json
└── story/
└── v1/
└── timeline.json

How to Make Changes

Your first step is to determine if your change is "Breaking" or "Non-Breaking."


A. Making a Non-Breaking Change

A non-breaking (or backward-compatible) change does not violate the contract for existing consumers of the schema.

Examples of Non-Breaking Changes:

  • Adding a new optional field.
  • Adding a new value to an enum (provided consumers are built to handle unknown values gracefully).
  • Adding a non-required property to an object.

How to Implement:

  1. Locate the schema file in the latest existing version folder (e.g., src/effect/v1/main.json).
  2. Apply your changes directly to that file.
  3. Commit your changes. No new folders or files are needed.

B. Making a Breaking Change

A breaking (or backward-incompatible) change will cause existing data or clients to fail validation. We must introduce a new version to handle these changes safely.

Examples of Breaking Changes:

  • Removing a field.
  • Renaming a field.
  • Changing a field's data type (e.g., string to integer).
  • Making an optional field required.
  • Adding a new required field (with no default value).
  • Adding a new validation rule (e.g., changing a string's maxLength).
  • Removing a value from an enum.

How to Implement: This process establishes the next global version for our schemas (e.g., v2).

  1. Identify the Schema: Locate the schema you need to modify (e.g., src/effect/v1/main.json).

  2. Create New Version Directory: Create a new version directory alongside the existing one. If you are changing a v1 schema, you will create a v2 directory.

    • mkdir -p src/effect/v2
  3. Copy-on-Write: Copy the schema from the previous version into the new directory. Do not move it.

    • cp src/effect/v1/main.json src/effect/v2/main.json
  4. Apply Your Change: Make your breaking change to the newly copied file (src/effect/v2/main.json).

  5. Leave the Old Version Untouched: The original src/effect/v1/main.json must not be modified.

Workflow in Practice

Let's walk through a development cycle where multiple changes occur. Our current latest version is v1.

Scenario 1: A breaking change is needed for effect schemas.

  • You need to rename the source_url field to sourceUrl in src/effect/v1/main.json.
  • Action: You create src/effect/v2/, copy main.json into it, and make the change there. This officially starts the "v2" generation of our schemas.

Scenario 2: A month later (in the same release cycle), a breaking change is needed for layers.

  • You need to change the opacity field in src/layers/v1/background.json from an integer 0-100 to a float 0.0-1.0.
  • Action: This change is part of the same global v2 update. You create src/layers/v2/, copy background.json into it, and apply the change there.

Result: The global v2 version now consists of:

  • src/effect/v2/main.json (new)
  • src/layers/v2/background.json (new)
  • src/story/v1/timeline.json (fallback from v1, since no v2 exists)

A v3 would only be created when we need to make a new breaking change to the already-released v2 set of schemas.

Guiding Principles (TL;DR)

  • Always check if your change is breaking. When in doubt, treat it as a breaking change.
  • To add an optional field, edit the latest version in place.
  • To make any other change, create a new version folder and copy the file.
  • Communicate with other teams when a new schema version is being introduced.