Schema Diffing¶
Tessera automatically compares schemas to detect breaking vs non-breaking changes.
How It Works¶
When you publish a new contract, Tessera:
- Fetches the current active contract
- Compares the schemas using JSON Schema rules
- Classifies each change as breaking or non-breaking
- Creates a proposal if any breaking changes are detected
Change Types¶
Property Changes¶
| Change | Backward | Forward |
|---|---|---|
| Add optional property | Safe | Breaking |
| Add required property | Breaking | Safe |
| Remove property | Breaking | Safe |
| Rename property | Breaking | Breaking |
Type Changes¶
| Change | Backward | Forward |
|---|---|---|
| Widen type (int → number) | Safe | Breaking |
| Narrow type (number → int) | Breaking | Safe |
| Change type (string → int) | Breaking | Breaking |
Required Changes¶
| Change | Backward | Forward |
|---|---|---|
| Make optional → required | Breaking | Safe |
| Make required → optional | Safe | Breaking |
Enum Changes¶
| Change | Backward | Forward |
|---|---|---|
| Add enum value | Safe | Breaking |
| Remove enum value | Breaking | Safe |
Examples¶
Safe Change (Backward Compatible)¶
// Before
{
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"}
}
}
// After - adding optional field
{
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"email": {"type": "string"} // New optional field
}
}
Result: Auto-published as minor version bump.
Breaking Change¶
// Before
{
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"email": {"type": "string"}
},
"required": ["id", "name", "email"]
}
// After - removing required field
{
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"}
},
"required": ["id", "name"]
}
Result: Proposal created, consumers must acknowledge.
Compatibility Modes¶
Backward (Default)¶
Consumers using the old schema can read new data.
Breaking changes: - Remove property - Add required property - Narrow type - Remove enum value
Forward¶
Producers using the old schema produce valid new data.
Breaking changes: - Add property (even optional) - Widen type - Add enum value
Full¶
Both backward and forward compatible. A change is breaking under full mode if it would be breaking under either backward or forward mode (the union of both sets). Changes that are benign under both backward and forward modes remain non-breaking.
Breaking changes: - Remove property (backward) - Add property (forward) - Rename property (both) - Change type incompatibly (both) - Narrow type (backward) or widen type (forward) - Add required field (backward) or remove required field (forward) - Remove enum value (backward) or add enum value (forward) - Tighten constraint (backward) or relax constraint (forward) - Remove default (backward) or add default (forward) - Remove nullable (backward) or add nullable (forward)
None¶
No compatibility checking - all changes are non-breaking.
API Response¶
When publishing, the response indicates what happened:
Or for breaking changes: