skip to content

When a schema registry enforces 'BACKWARD' compatibility mode on a service's request/response schema, what exactly does it check before allowing a new schema version to be registered, and how does that differ from 'FORWARD' and 'FULL' compatibility modes?

level: seniorimportance: should knowfreq 45%

answer

  1. BACKWARD: new reader, old data
  2. FORWARD: old reader, new data
  3. FULL = both directions
  4. registry rejects incompatible registration attempts
  5. checked schema-by-schema per subject

basics

~20 s

A schema registry checks new versions of a data format before allowing them to be published, using rules like 'can old readers still read new data' (forward) or 'can new readers read old data' (backward), and 'full' means both must hold at once.

solid answer

~50 s

A schema registry is a central service that stores every historical version of a schema (e.g., Protobuf, Avro, JSON Schema) for a given subject and validates each new version against a configured compatibility rule before allowing registration. BACKWARD compatibility checks that a reader using the new schema can correctly read data written with the old schema - it permits removing fields (readers just ignore what's not requested) and adding fields with defaults, but forbids removing required fields without defaults or renaming fields. FORWARD compatibility checks the opposite: a reader using the old schema must still be able to read data written with the new schema - it permits adding fields (old readers ignore new ones) but forbids removing fields old readers still expect. FULL compatibility requires both simultaneously, which is the strictest and safest mode for a widely-shared contract with many independently-deployed readers and writers, at the cost of being the most restrictive about what changes are even allowed.

go deeper

for a junior

Knows a schema registry stores schema versions and can name that there are different compatibility settings, without needing precise BACKWARD/FORWARD definitions.

for a middle

Can correctly state the BACKWARD vs FORWARD distinction (which side is 'new', which is 'old') with a simple example of what's allowed under each.

for a senior

Chooses the right compatibility mode for a given deployment pattern, explains FULL's trade-off, and knows how to handle a legitimate breaking change under a strict mode via telemetry-informed override or new subject.

for a principal

Sets registry compatibility policy as org-wide platform standard, decides when NONE/manual override is acceptable and under what governance, and weighs registry-enforced contracts against consumer-driven contract testing for different classes of interfaces.

## What a schema registry does A **schema registry** is a centralized store and gatekeeper for every version of a data schema associated with a particular contract, referred to as a 'subject' (commonly one per service-interface or per message type). Its core mechanism is straightforward: whenever a team wants to register a new version of a schema, the registry runs an automated compatibility check between the new schema and the prior version(s) according to a configured compatibility mode, and it rejects the registration outright if the check fails. This moves compatibility enforcement out of code review intuition and into an automated, mechanical gate that runs the same way every time, for every schema, regardless of which team is publishing it. ## The modes, and what each one asks The specific modes encode two different questions about who reads what. | Mode | The question it puts to a new schema version | |---|---| | **BACKWARD** | 'if I upgrade my reader to the new schema, can it still correctly interpret data that was written using the old schema?' | | **FORWARD** | 'if data is written using the new schema, can a reader still running the old schema correctly interpret it?' | | **FULL** | both directions, simultaneously | **BACKWARD** compatibility asks the first of those. This is the mode you need when you deploy new consumers before old data or old producers have been fully retired - the new reader must tolerate old-shaped data. Under BACKWARD rules: - you may remove a field (a new reader simply won't look for it); - you may add a field as long as it has a default value (so old data that lacks it still parses cleanly); - but you may not add a field without a default and require it, and you generally may not change a field's type. **FORWARD** compatibility asks the opposite question. This is the mode you need when producers upgrade before all consumers have upgraded - old readers must tolerate new-shaped data. Under FORWARD rules: - you may add new fields (old readers just ignore fields they don't recognize); - but you may not remove a field that old readers still expect to find. **FULL** compatibility requires both BACKWARD and FORWARD to hold simultaneously between consecutive versions, which in practice restricts changes to the safest subset: you can add optional fields with defaults, but you generally cannot remove any field or add any field without a default, because either action would violate one direction or the other. ## Why the gate exists at all The reason this exists is that in a system with many independently-deployed producers and consumers of a shared data shape, you cannot rely on human review alone to catch every subtle incompatibility, and you cannot assume every producer and consumer upgrades atomically at the same instant - there is always a window where old and new code coexist. The registry turns 'did we just break someone' from a question answered after an incident into a question answered at registration time, before the new schema can even be published and used. ## The trade-off The trade-off is **expressiveness versus safety**. - **FULL** compatibility is the safest choice when a schema has many independent consumers you can't coordinate with directly - but it's also the most restrictive, forbidding genuinely useful cleanups like removing a field everyone has actually stopped using, unless you first prove via other means (usage telemetry, an explicit deprecation window) that it's truly safe and then do a one-time mode change or manual override. - **BACKWARD-only** is more permissive (you can remove fields freely) but assumes producers upgrade at their own pace while readers upgrade first, which fits systems where a small number of readers integrate against many possible historical data shapes. Choosing the wrong mode for your actual deployment pattern produces exactly the outage you were trying to prevent, just delayed. ## Failure modes Failure modes are usually organizational rather than technical. - A team sets the compatibility mode too loosely (e.g., NONE, meaning no check at all) to unblock a deploy under time pressure, ships an incompatible change, and only discovers the break when a consumer team's parsing starts failing in production - by which point the registry's whole value has been bypassed. - Another common failure is setting FULL compatibility on a schema that genuinely needs a breaking change, which then blocks legitimate registrations indefinitely until someone manually overrides the check or creates an entirely new subject/version namespace for a fresh major version. ## Where it shows up in practice A concrete real-world example: **Confluent Schema Registry**, widely used alongside Avro and Protobuf schemas for structured service contracts, defaults new subjects to BACKWARD compatibility and lets teams configure FORWARD, FULL, or NONE per subject; its registration API returns an explicit compatibility-check failure with the specific incompatible field named, directly in the response to a failed schema-registration call, giving the publishing team immediate, actionable feedback rather than a downstream production surprise.

  • Why would a team choose FULL compatibility mode over BACKWARD-only, given that FULL is more restrictive about what changes are allowed?
    FULL is the right choice when a schema has many independently-deployed readers and writers that can't be coordinated to upgrade in a specific order - you don't know whether a new reader will see old data or an old reader will see new data first, so you need both directions to hold safely at all times. BACKWARD-only is a reasonable, more permissive choice only when you can be confident readers always upgrade ahead of writers.
  • What should a team do if a schema registered under FULL compatibility genuinely needs to drop a field that both BACKWARD and FORWARD checks would reject?
    They typically either confirm via usage telemetry that no live reader or writer still depends on the field and then perform a manual, explicitly reviewed override or migrate to a new subject/major version namespace, rather than weakening the compatibility mode globally. This keeps the automated safety net intact for every other change while still allowing a deliberate, audited breaking change when it's truly justified.
  • How does compatibility mode NONE differ from the other modes, and why is it risky?
    NONE disables automated compatibility checking entirely, so the registry will accept any new schema version regardless of whether it breaks existing readers or writers. It's risky because it removes the registry's core safety guarantee - teams sometimes set it under deadline pressure to unblock a deploy, which reintroduces exactly the class of silent-breakage incidents the registry exists to prevent.

Like a translator checking a new phrasebook edition two ways: can someone using the new book still understand old letters (backward), and can someone still using the old book understand new letters (forward) - requiring both is the strictest, safest standard.

saying these in an interview costs you the question

  • can't state which direction BACKWARD vs FORWARD each check
  • thinks the registry only matters for message queues and has no bearing on RPC/service contracts
  • assumes FULL compatibility allows removing fields freely
  • doesn't know the registry can outright reject a registration attempt
  • conflates compatibility mode with semantic versioning MAJOR/MINOR without understanding they're checking different things

context