Skip to main content
This tutorial takes an Avro schema through its full life: register it, produce and consume records with it, then change it—first in a way that fails the compatibility check, then in a way that passes. The failure is the point. Seeing the registry reject a change is what makes the compatibility rules concrete. Allow about 20 minutes.

Prerequisites

  • A Kafka cluster, or a Pulsar cluster with the Kafka protocol enabled, on StreamNative Cloud.
  • An API key for a service account with the schema-manager role, plus produce and consume permissions on the topic.
  • Java 17 or later and Maven, for the producer and consumer.
  • curl and jq.
Set up your shell:
See Connect for how to find these.

Step 1: Create a topic

Step 2: Define and register a schema

Create payment.avsc:
Register it under the payments-value subject:
That ID is what every record will carry. Confirm the subject exists:

Step 3: Build a producer

Add the dependencies:
Configure and send:

Step 4: Consume the records

The consumer never sees payment.avsc. It reads the schema ID from each record’s prefix and fetches the schema from the registry—which is the whole point of the registry.

Step 5: Make an incompatible change

Add a required field with no default. Create payment-v2-bad.avsc:
Test it before registering:
The subject’s default mode is BACKWARD, which requires that a consumer on the new schema can read data written under the old one. The five records you produced have no currency, and the new schema gives the reader nothing to substitute—so the change is rejected. Try to register it anyway:
HTTP 409. The registry stopped a change that would have broken every consumer of the existing data.

Step 6: Fix it

Give the field a default. Create payment-v2.avsc:
A new schema ID and a new version:
Now a consumer on v2 reading a v1 record gets currency = "USD"—the default fills the gap. That single word is the difference between a safe change and a broken pipeline.

Step 7: Change the compatibility mode

Sometimes you genuinely need a breaking change. Loosen the mode deliberately rather than working around the check:
Now payment-v2-bad.avsc registers. Set the mode back when you’re done:
NONE disables the guarantee, it doesn’t make old consumers able to read new data. Use it only when you control every consumer and can coordinate the rollout.
GET /config/payments-value reports the real value. The global GET /config always returns NONE regardless of what’s set—see Confluent API compatibility.

Clean up

What to take away

  • A schema ID travels in each record; the consumer resolves it from the registry rather than being told the schema out of band.
  • BACKWARD, the default, means new-schema consumers must be able to read old data—so upgrade consumers before producers.
  • Defaults are what make a field addition compatible in Avro.
  • Test with /compatibility/... in CI, so an incompatible change fails the build instead of the deploy.

Next steps

Evolution and compatibility

Every mode, and which side to upgrade first.

Manage schemas

A registration workflow that holds up in production.