skip to content

A topic's schema subject in a message schema registry is set to BACKWARD compatibility mode. What does that mode actually guarantee, and how does it differ from FORWARD and FULL compatibility modes?

level: middleimportance: must knowfreq 80%

answer

  1. BACKWARD = new reader, old data
  2. FORWARD = old reader, new data
  3. FULL = both directions
  4. transitive = checked against all prior versions, not just last
  5. additions need defaults, deletions need prior defaults

basics

~20 s

BACKWARD compatibility means new schema versions can still be read using the code built for the old schema. FORWARD is the opposite: old code can read data written with the new schema. FULL means both directions work at once.

solid answer

~60 s

BACKWARD compatibility means a consumer using the latest schema can read data produced with an older schema version; practically this means you may add optional (defaulted) fields and remove fields that had a default, but you can't remove a required field or make an optional field required, because old data wouldn't satisfy the new reader. FORWARD is the mirror image: data produced with the new schema can be read by a consumer still using an older schema, so you can add fields freely (old readers ignore them) but removing a field is fine only if it had a default in the old schema. FULL requires both directions to hold simultaneously, which is the strictest and safest for independent producer/consumer deploy order, but is the most restrictive on what changes are allowed. The practical decision driver is deploy order: BACKWARD assumes consumers upgrade before or after producers safely because they can read old-format data with new schema; FORWARD assumes producers can roll ahead while consumers lag; FULL removes the need to reason about deploy order at all, at the cost of fewer allowed schema changes.

go deeper

for a junior

Should know that these modes control which direction of schema change is safe, in plain terms: can new code read old data, or can old code read new data.

for a middle

Should correctly state what each of BACKWARD, FORWARD, and FULL allows and forbids for field additions/removals and defaults, using an Avro-style example.

for a senior

Should reason about which mode to pick based on actual producer/consumer deploy order in their system, and explain transitive variants and why version-lag matters.

for a principal

Should design subject-level compatibility policy across an organization, including when to force a new subject/major version instead of stretching compatibility rules, and how to communicate the policy so teams don't fight the registry.

## The question the modes answer Schema compatibility modes exist to answer one operational question precisely: in what order can producers and consumers of a topic be deployed relative to each other without one side crashing or silently misinterpreting the other's data? A registry evaluates every newly-registered schema version against the currently active version (or, in transitive modes, against all prior versions) using one of these named rules, and rejects registration if the rule is violated. | Mode | Reader and data | What it permits | |---|---|---| | `BACKWARD` | new reader, old data | adding a new field as long as it has a default value; deleting a field that had a default | | `FORWARD` | old reader, new data | adding fields freely; removing a field only if that field had a default | | `FULL` | both directions at once | essentially every field addition or removal must carry a default | ## BACKWARD **BACKWARD** compatibility means a schema reader built against the new (latest) schema can correctly read data that was written using the immediately prior schema version. Concretely for Avro this permits: - adding a new field as long as it has a default value (an old record lacking that field is filled in with the default when read by new code), and - deleting a field that had a default in the old schema (new code simply never sees it, which is fine since it never required it as mandatory). What BACKWARD compatibility forbids is: - deleting a field that had no default (new code has no way to fill it in when reading old data), or - adding a field with no default (old data won't have it, and new code that requires it has nothing to read). The operational implication is: consumers must upgrade to understand new data, but you're always safe to upgrade consumers first and let them read old-format backlog, because that's exactly what BACKWARD guarantees. This is Confluent's default mode and the most commonly seen in practice because Kafka topics retain historical data that new consumers must be able to replay. ## FORWARD **FORWARD** compatibility flips the direction: a reader using the old schema must be able to read data written with the new schema. This permits adding fields freely (an old reader simply doesn't look for fields it doesn't know about and ignores them) but only allows removing a field if that field had a default in the old schema (so the old reader, expecting the field, gets the default instead of an error). FORWARD is the right mode when you expect producers to roll out ahead of consumers, for instance a service emitting events where downstream consumer teams update on a slower, less coordinated cadence, and you want producers free to add data without breaking whoever hasn't upgraded yet. ## FULL and the transitive variants **FULL** compatibility requires both BACKWARD and FORWARD to hold at once: new schema can read old data, and old schema can read new data. This is the safest choice when you cannot control or predict the deploy order between producers and consumers, for example a shared platform topic consumed by many teams on independent release trains, where you have no way to guarantee anyone upgrades before or after anyone else. The cost is that FULL is the most restrictive: essentially every field addition or removal must carry a default, since both directions need to gracefully handle the field's presence or absence. There are also transitive variants (BACKWARD_TRANSITIVE, FORWARD_TRANSITIVE, FULL_TRANSITIVE) that check compatibility against all previous schema versions, not just the immediately prior one, which matters when a consumer might be several versions behind rather than exactly one behind, a common real situation when a service hasn't redeployed in months. ## The trade-off The trade-off across all modes is **expressiveness versus safety**. A looser or absent compatibility check lets you make any change you want, including ones that will crash a consumer in production the moment it encounters a message it can't decode; a stricter mode like FULL_TRANSITIVE guarantees safety across arbitrary deploy orders and version lag but forces every evolution to be additive-with-defaults, ruling out renames, type changes, or genuinely required new fields without a new subject/topic (a 'major version bump' by convention, e.g., orders-v2). ## Failure modes Failure modes show up as either: 1. **registry rejections** — a producer's deploy pipeline fails at schema registration because the new schema violates the subject's compatibility rule, annoying but safe, since it is caught before any bad data is written; or, 2. worse, as **runtime deserialization exceptions** in a consumer when compatibility mode was set to NONE or was misconfigured for the team's actual deploy pattern, so an incompatible change slipped through and a live consumer starts throwing on every new message. ## Where it shows up A concrete scenario: an e-commerce platform's `orders-value` subject is BACKWARD_TRANSITIVE. The catalog team wants to remove a legacy `internalSku` field that has been unused for a year. Because the field has no default in any prior schema version, the registry rejects the removal outright. The team first ships a schema version that adds a default to `internalSku`, waits a deployment cycle, then removes it in a follow-up version, two safe, registry-approved steps instead of one risky one.

  • Why would a team choose FORWARD compatibility instead of the more commonly-used BACKWARD default?
    FORWARD fits scenarios where producers are expected to evolve and deploy ahead of consumers, such as a core platform team publishing enriched events that many downstream teams consume on their own slower cadence. It lets the producer add new fields freely without waiting for every consumer to catch up, at the cost of restricting how producers can remove fields.
  • What is the difference between BACKWARD and BACKWARD_TRANSITIVE in practice?
    BACKWARD only checks the new schema against the immediately previous version, so a consumer exactly one version behind is safe, but a consumer several versions behind might not be. BACKWARD_TRANSITIVE checks the new schema against every prior version in the subject's history, guaranteeing safety for consumers lagging by any number of versions, which matters for services that redeploy infrequently.
  • If a compatibility mode rejects a needed schema change, such as making an optional field required, what is the standard escape hatch?
    The common pattern is a two-step or multi-step migration: first add the new required-in-spirit field as optional with a default and let it populate for a while, then in a later version tighten constraints once all producers are confirmed to be sending it, or as a last resort create a new subject/topic representing a major version bump rather than force an incompatible change through the existing one.

Think of translators between two people speaking evolving dialects of the same language: BACKWARD means the newer speaker can still understand everything said in the older dialect; FORWARD means the older speaker can still follow what's said in the newer dialect; FULL means neither side ever gets confused no matter who spoke when.

saying these in an interview costs you the question

  • Says BACKWARD and FORWARD mean the same thing
  • Claims FULL compatibility allows any kind of schema change as long as it's registered
  • Cannot explain why adding a required field with no default breaks BACKWARD compatibility
  • Thinks compatibility mode is a property of the message rather than the subject
  • Doesn't know that removing a field requires it to have had a default in the version being removed from

context