Schema evolution is at the heart of running Kafka in production. Pick the wrong compatibility mode and consumers will fail to read data mid-rollout. CCDAK in particular loves to ask about which side you update first and how that maps to compatibility modes.
This article walks through the essence of BACKWARD / FORWARD / FULL, the transitive variants, how they line up with deployment strategy, and the common pitfalls — all aligned with the official documentation. The final section includes a REST API example and a practice question.
Compatibility modes are how Schema Registry validates, at registration time, whether a new schema can be safely read and written compared to the previous (or historical) schema. The key question is which side you roll out first.
BACKWARD guarantees that consumers on the new schema can read data produced under the old schema — best when consumers go first. FORWARD guarantees that consumers on the old schema can read data produced under the new schema — best when producers go first. FULL satisfies both directions at once, and is the right choice when the mixed-version window is long or you genuinely need two-way compatibility.
| Mode | Compatibility guarantee | Rollout direction | Typical safe changes |
|---|---|---|---|
| BACKWARD | New-schema consumers can read old data | Consumers first | Adding fields (defaults required), type promotion (within Avro's rules) |
| FORWARD | Old-schema consumers can read new data | Producers first | Removing fields (defaults fill in on the old side), compatible type changes |
| FULL | Both BACKWARD and FORWARD | Bidirectional / mixed | Cautious additions, removals, and type changes (only what works both ways) |
| NONE | No validation | None | None |
Rollout direction vs. compatibility mode (conceptual diagram)
時間 -->
消費者先行(BACKWARD):
Consumer v2 (new schema)
^ ^ 読める
| |
Consumer v1 <- Data by Producer v1/v2
生産者先行(FORWARD):
Data by Producer v2 (new schema) -> Consumer v1 (old schema) 読める
^ 生産者を先に切替
FULL(双方向):
Producer v1/v2 混在 <-> Consumer v1/v2 混在
どちらの組み合わせでも読めることを要求BACKWARD and FORWARD each come in two flavors: a regular mode that only compares against the immediately previous version, and a transitive mode (_TRANSITIVE) that compares against every version in the history.
For long-lived topics or environments where many applications update incrementally, the transitive mode is the safer default. The regular mode is reasonable when you can guarantee every client will catch up quickly.
Schema Registry supports Avro, JSON Schema, and Protobuf, but compatibility checks follow each format's resolution rules. Below are representative patterns generally considered safe in practice (the details depend on each official spec).
In Avro, default values are critical — they largely determine whether adds and removes are safe. In Protobuf, the no-reuse rule for field numbers and disciplined reservation management are key.
If your rollout order lines up with the compatibility mode, you can survive a long mixed-version window without incidents. When they do not match, unreadable data starts appearing partway through the rollout.
Subject naming strategy (TopicNameStrategy / RecordNameStrategy / TopicRecordNameStrategy) also shapes your evolution plan. If you reuse records or share schemas across topics, consider a RecordNameStrategy variant so you can control blast radius at the subject level.
Compatibility can be set globally and per subject. The safe default is to keep the global setting conservative and only override the exceptional subjects.
Always run a pre-flight check against the compatibility API before applying to production, and wire it into CI.
Example: setting compatibility mode and running a pre-flight check (Avro, application/json)
## グローバル互換性をFULL_TRANSITIVEに設定
curl -s -X PUT \
-H "Content-Type: application/json" \
--data '{"compatibility": "FULL_TRANSITIVE"}' \
http://localhost:8081/config
## サブジェクト単位で上書き(topic-valueをBACKWARDに)
curl -s -X PUT \
-H "Content-Type: application/json" \
--data '{"compatibility": "BACKWARD"}' \
http://localhost:8081/config/my-topic-value
## 既存バージョン(latest)との互換性を事前チェック
NEW_SCHEMA='{
"schema": "{\"type\":\"record\",\"name\":\"User\",\"fields\":[{\"name\":\"id\",\"type\":\"long\"},{\"name\":\"name\",\"type\":\"string\",\"default\":\"\"}]}"
}'
curl -s -X POST \
-H "Content-Type: application/json" \
--data "$NEW_SCHEMA" \
http://localhost:8081/compatibility/subjects/my-topic-value/versions/latest
## 問題なければ登録
curl -s -X POST \
-H "Content-Type: application/json" \
--data "$NEW_SCHEMA" \
http://localhost:8081/subjects/my-topic-value/versionsOn CCDAK, mixing up the compatibility name and the rollout direction is the classic trap. BACKWARD means 'new reads old'; FORWARD means 'old reads new'. Drill the direction until it is muscle memory.
Other frequent topics: TRANSITIVE vs. non-transitive, field defaults, and Protobuf field number rules. Remember that the compatibility check is a mechanical comparison against the previous version or the full history — it cannot detect semantic breakage.
CCDAK
問題 1
Existing consumers (on the old schema) cannot be changed for the time being, but you want to deploy producers first and add a new field. Which compatibility mode is appropriate?
正解: A
For a producers-first rollout, FORWARD is the right choice because it guarantees that old-schema consumers can read the new data. FULL would also satisfy the requirement, but the question focuses on read safety for old consumers only, so FORWARD is the minimum match.
What is the difference between BACKWARD and BACKWARD_TRANSITIVE?
BACKWARD only requires compatibility with the immediately previous version, while BACKWARD_TRANSITIVE requires compatibility with every version in the history. If old data persists for a long time or old consumers remain in production, TRANSITIVE is the safer choice.
Do JSON Schema and Protobuf follow the same compatibility rules as Avro?
No. Compatibility checks rely on format-specific resolution rules. For example, Protobuf forbids reusing field numbers, and changing a number is breaking. In JSON Schema, making fields required or tightening constraints is typically breaking. Always confirm the official spec for the format you are using before going to production.
Is it acceptable to temporarily switch to NONE in production just to push a schema through?
It does happen in the field as a brief emergency measure, but it is not something we strongly recommend. If you must do it, scope it to a single subject, restore the original mode immediately afterwards, strengthen pre-flight compatibility checks in CI, and rigorously review the blast radius.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
Kafka Topics & Partitions: Distribution Fundamentals (2026)
How Kafka topics and partitions enable scale — ordering guar...
CCDAK Exam Guide: Confluent Certified Developer (2026)
Complete prep for the CCDAK exam — Producer/Consumer API, St...
CCAAK Exam Guide: Confluent Certified Administrator (2026)
Pass the CCAAK exam — cluster management, partitions, securi...
Kafka Replicas & ISR: Fault Tolerance Explained (2026)
Replica placement, in-sync replicas (ISR), leader election. ...
Kafka Offsets: Commit Modes & Consumer Position (2026)
Offset semantics — auto vs. manual commit, __consumer_offset...