Mehdi Akiki
Published on

What Schema Registry Compatibility Modes Actually Protect

Authors
  • Mehdi Akiki avatar
    Name
    Mehdi Akiki
    Twitter

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:

ModeReader/writer directionHistory checked
BACKWARDnew reads previouslatest
BACKWARD_TRANSITIVEnew reads oldall registered history
FORWARDprevious reads newlatest
FORWARD_TRANSITIVEold reads newall registered history
FULLbothlatest
FULL_TRANSITIVEbothall registered history
NONEno compatibility gatenone

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.