Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Schema Compatibility

Schema compatibility rules govern how schemas may evolve while maintaining interoperability between producers and consumers.


Schema EvolutionProducersConsumersSchema V1Schema V2Schema V3Producer A(uses V3)Producer B(uses V2)Consumer X(uses V3)Consumer Y(uses V2)Consumer Z(uses V1)Compatibility ensures consumerscan read data from all compatibleschema versionsEvolutionEvolution

ModeDescriptionUse Case
BACKWARDNew schema can read old dataDefault. Consumer upgrades first
BACKWARD_TRANSITIVENew schema can read all previous versionsStrict backward compatibility
FORWARDOld schema can read new dataProducer upgrades first
FORWARD_TRANSITIVEAll previous schemas can read new dataStrict forward compatibility
FULLBoth backward and forward compatibleMost restrictive
FULL_TRANSITIVEFull compatibility with all versionsMaximum safety
NONENo compatibility checkingDevelopment only

New schema versions must be able to read data written with the previous schema version.

ChangeBackward CompatibleReason
Add optional field with defaultYesNew consumers ignore unknown defaults
Remove fieldYesNew consumers don’t need it
Change optional to requiredNoOld data lacks required field
Add required fieldNoOld data lacks field
Change field typeUsually NoType mismatch
// Schema V1
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"}
]
}
// Schema V2 (backward compatible)
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"},
{"name": "phone", "type": ["null", "string"], "default": null}
]
}
1. Upgrade consumers to V2
2. Verify consumers handle V1 and V2 data
3. Upgrade producers to V2

Old schema versions must be able to read data written with the new schema version.

ChangeForward CompatibleReason
Add fieldYesOld consumers ignore unknown fields
Remove optional field with defaultYesOld consumers use default
Remove required fieldNoOld consumers expect field
Add required field without defaultNoOld consumers can’t handle
// Schema V1
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"},
{"name": "legacy_field", "type": ["null", "string"], "default": null}
]
}
// Schema V2 (forward compatible)
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"}
]
}
1. Upgrade producers to V2
2. Verify old consumers handle V2 data
3. Upgrade consumers to V2

Both backward and forward compatible. Most restrictive mode.

ChangeFull Compatible
Add optional field with defaultYes
Remove optional field with defaultYes
Add required fieldNo
Remove required fieldNo
Rename fieldNo
Change field typeNo
// Schema V1
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"},
{"name": "status", "type": ["null", "string"], "default": null}
]
}
// Schema V2 (full compatible - added optional field)
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"},
{"name": "status", "type": ["null", "string"], "default": null},
{"name": "role", "type": ["null", "string"], "default": null}
]
}
// Schema V3 (full compatible - removed optional field)
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "string"},
{"name": "email", "type": "string"},
{"name": "role", "type": ["null", "string"], "default": null}
]
}

Transitive modes check compatibility against all previous versions, not just the immediately preceding one.

ModeChecks Against
BACKWARDV(n-1) only
BACKWARD_TRANSITIVEV1, V2, …, V(n-1)
FORWARDV(n-1) only
FORWARD_TRANSITIVEV1, V2, …, V(n-1)
FULLV(n-1) only
FULL_TRANSITIVEV1, V2, …, V(n-1)
  • Long-lived data with multiple schema versions
  • Consumers may read historical data from any version
  • Strict compliance requirements
  • Data reprocessing scenarios

Terminal window
# Set global default
curl -X PUT http://schema-registry:8081/config \
-H "Content-Type: application/vnd.schemaregistry.v1+json" \
-d '{"compatibility": "BACKWARD"}'
# Get global config
curl http://schema-registry:8081/config
Terminal window
# Set subject-specific compatibility
curl -X PUT http://schema-registry:8081/config/users-value \
-H "Content-Type: application/vnd.schemaregistry.v1+json" \
-d '{"compatibility": "FULL"}'
# Get subject config
curl http://schema-registry:8081/config/users-value
Terminal window
# Test if schema is compatible
curl -X POST http://schema-registry:8081/compatibility/subjects/users-value/versions/latest \
-H "Content-Type: application/vnd.schemaregistry.v1+json" \
-d '{
"schema": "{\"type\":\"record\",\"name\":\"User\",\"fields\":[{\"name\":\"id\",\"type\":\"string\"}]}"
}'
# Response
{"is_compatible": true}

ChangeBackwardForwardFull
Add field with defaultYesYesYes
Add field without defaultNoYesNo
Remove field with defaultYesYesYes
Remove field without defaultYesNoNo
Rename field (with alias)YesYesYes
Change field typeSee belowSee belowSee below

Avro Type Promotions (Allowed):

FromTo
intlong, float, double
longfloat, double
floatdouble
stringbytes
bytesstring
ChangeSafe
Add fieldYes
Remove fieldYes (deprecated recommended)
Rename fieldYes (field number unchanged)
Change field numberNo
Change field typeNo (except compatible types)
Change repeated to optionalNo

Protobuf Best Practices:

// V1
message User {
string id = 1;
string email = 2;
}
// V2 - Safe evolution
message User {
string id = 1;
string email = 2;
string phone = 3; // New optional field
reserved 4; // Reserve for future use
reserved "legacy_field"; // Reserve removed field name
}
ChangeBackwardForward
Add optional propertyYesYes
Add required propertyNoYes
Remove propertyYesNo
Make required optionalYesNo
Make optional requiredNoYes
Narrow type constraintNoYes
Widen type constraintYesNo

Write data in both old and new formats during transition.

1. Deploy new schema version
2. Update producers to write both formats
3. Migrate consumers to new format
4. Remove old format writes

Create new topic for new schema version.

1. Create new topic with new schema
2. Deploy consumers reading both topics
3. Switch producers to new topic
4. Drain old topic
5. Remove old topic consumers

Evolve schema within same topic (requires compatibility).

1. Register compatible schema version
2. Deploy consumers (backward compatible)
3. Deploy producers (forward compatible)

Terminal window
# Get detailed compatibility check
curl -X POST http://schema-registry:8081/compatibility/subjects/users-value/versions/latest?verbose=true \
-H "Content-Type: application/vnd.schemaregistry.v1+json" \
-d '{"schema": "..."}'
ErrorCauseSolution
Schema being registered is incompatibleViolates compatibility rulesModify schema or change compatibility mode
Reader expected field not present in writerMissing required fieldAdd default value to field
Type mismatchIncompatible type changeUse union types or new field
Terminal window
# List all versions
curl http://schema-registry:8081/subjects/users-value/versions
# Compare schemas
# Fetch V1 and V2, compare manually or use schema tools
curl http://schema-registry:8081/subjects/users-value/versions/1
curl http://schema-registry:8081/subjects/users-value/versions/2