- Published on
What Schema Registry Compatibility Modes Actually Protect
- Authors

- Name
- Mehdi Akiki
Reference
A Schema Registry compatibility check answers a narrow question: can schemas relate under the selected format and mode?
It does not know whether the old consumer is still running, whether a replay contains older events, or whether a default value tells the truth.
I use the mode as one gate inside a deployment contract, not as the entire contract.
Start with reader and writer direction
The stable definitions are:
backward: new reader can read old writer data
forward: old reader can read new writer data
full: both directions
For concrete added and removed field examples, see Backward, Forward, and Full Compatibility With Concrete Events.
The registry adds a second dimension: how much history is checked.
non-transitive: compare with a selected recent schema, commonly latest
transitive: compare with every relevant registered historical schema
The common mode matrix
Confluent Schema Registry exposes these mode families:
| Mode | Reader/writer direction | History checked |
|---|---|---|
BACKWARD | new reads previous | latest |
BACKWARD_TRANSITIVE | new reads old | all registered history |
FORWARD | previous reads new | latest |
FORWARD_TRANSITIVE | old reads new | all registered history |
FULL | both | latest |
FULL_TRANSITIVE | both | all registered history |
NONE | no compatibility gate | none |
The exact registry implementation and subject configuration matter. The Schema Registry evolution documentation is the primary reference for these modes.
Mode selection implies a rollout direction
Suppose consumers are upgraded before producers.
During the rollout, new consumers still read old events, so backward compatibility is central:
deploy new reader
old writer continues
deploy new writer later
If producers deploy first, old consumers must read new data, so forward compatibility matters:
deploy new writer
old readers continue
deploy readers later
Full compatibility permits more flexible overlap structurally, but does not guarantee that both application versions interpret the data the same way.
I record the actual deployment order and maximum mixed-version period beside the registry mode.
Latest-only checks can miss a long-lived consumer
Imagine:
V1: field account_id required
V2: add field region with default
V3: remove account_id under a rule compatible with V2 in one direction
A check only against V2 may pass while a V1 consumer or retained V1 event still matters.
Transitive checking widens the structural comparison to registered history. It is useful when events live a long time, consumers upgrade slowly, or replay is a product feature.
It only covers versions present under the subject and history the registry retains.
Subject naming determines which schemas meet
A compatibility mode is applied within a registry subject. If teams register related producers under different subjects, the registry may never compare them.
Conversely, putting unrelated record types into one subject can reject changes that never share a reader.
I define:
which producers write the subject
which consumers read it
how topic, record, or field naming maps to the subject
whether several event types share one stream
how aliases and references are resolved
The subject boundary should match the real compatibility community.
NONE is not a migration plan
Temporarily disabling compatibility can be legitimate for a controlled replacement topic or one-time migration. It should include:
owner and expiry
old and new topic/subject
backfill or bridge plan
consumer cutover evidence
rollback position
rule that re-enables enforcement
Leaving NONE in place because one deployment was blocked converts a useful incident signal into delayed consumer failure.
Enforcement must sit on every production write path
A registry cannot protect events that bypass it. I inventory normal producers, repair tools, replay jobs, connector-generated schemas, test utilities with production credentials, and administrative APIs.
A producer embedding a schema once at startup may also continue writing after registry policy changes. I verify how the client resolves and caches schema IDs and what happens when registration is rejected.
For emergency production repair, I keep a governed override with exact subject, schema hash, owner, reason, expiry, and downstream compatibility evidence. A hidden command that writes raw bytes directly to the topic defeats both the registry check and the audit trail.
Registry success does not protect semantics
These changes may pass structural checks and still break the product:
- defaulting unknown currency to USD;
- changing milliseconds to seconds without changing the integer type;
- reusing an identifier for a different entity;
- changing whether an empty list means “clear” or “leave unchanged”;
- changing a field used as a partition key;
- adding a value that makes old exhaustive application logic fail;
- changing authorization meaning while the schema stays identical.
The registry does not execute the business invariant.
I attach semantic contract tests with old payload fixtures and expected domain values.
Generated code and transport paths matter
The same schema can travel through:
binary event -> generated object -> JSON gateway -> generic map -> binary event
An intermediate conversion can discard unknown fields, coerce numbers, or replace missing with defaults. A direct schema compatibility check does not test this entire path.
For Protobuf specifically, Unknown Fields Are the Quiet Engine of Protobuf Evolution covers the preservation and round-trip details.
I run round-trip tests through the actual application adapters.
My release evidence
For a schema change I save:
subject and compatibility mode
versions compared by the registry
oldest event retained or replayable
consumer versions currently deployed
producer and consumer rollout order
old/new reader-writer fixture results
semantic assertions and defaults
round-trip results through gateways
rollback and topic migration plan
I alert on rejected registrations and on clients bypassing the registry, but a high pass rate is not a quality metric.
Compatibility modes protect schema-level reader/writer relationships inside their configured subject and history. That is valuable. Deployment overlap, data meaning, operational history, and application behaviour remain my responsibility.