Home

Tech Blogs · April 8, 2026 · 4 min read

Why payments teams move to Avro on Kafka

KafkaAvroSchema RegistryBackend

Plain JSON Kafka worked fine, until it didn't. Once the payments domain hit production scale, schema drift, bloated payloads and contract breaks became the team's biggest operational headache. Here is why Avro changed that.

~60%
smaller payloads
0
silent schema breaks
1
source of schema truth

The problem with raw Kafka in payments

Kafka at its core is just a log of bytes. Producers write whatever they want; consumers read and hope it matches. In a low-traffic internal tool that is fine. In a payments domain it is a liability. A transactionType field that silently changes from "CREDIT" to "credit" can break downstream reconciliation.

  • A producer renames a field

    Consumers are not told, and processing silently degrades.

  • A new team starts consuming payment.processed

    They do not know which fields to expect, so they reverse-engineer the topic from logs.

Why it matters. Neither case is acceptable in fintech.

What Avro brings to the table

Avro is a compact binary format where every message is tied to a versioned schema. Paired with Confluent Schema Registry, the schema lives in a central store: producers register it, consumers fetch it. No out-of-band docs, no tribal knowledge.

Think of Schema Registry as a contract ledger. Producers sign their messages with a schema ID. Consumers verify against it before processing. If the schema is incompatible, the message is rejected at write time, not discovered at 2am on an on-call rotation.

A safe change flows through

Producer. The team adds a nullable field to the payment schema and publishes with the new version.

Try both changes. A safe one flows through to consumers; a breaking one stops at the registry.

Avro enforces backward and forward compatibility rules. You can add a nullable field (backward compatible, so old consumers ignore it). You cannot rename a required field without a version bump. That discipline is what a payments team needs when several services consume the same topic.

A worked example: the "CREDIT" that became "credit"

Illustrative example

The same one-word change, with and without a schema

  • Without a schema: a producer starts sending "credit" instead of "CREDIT". Kafka accepts it, because it is only bytes. The consumer's reconciliation job compares strings, so credits stop matching. Someone finds the gap at end-of-day reconciliation.
  • With an Avro enum: transactionType is declared as an enum with the symbols CREDIT and DEBIT. The producer's serializer refuses to write "credit", because it is not a valid symbol. The bug fails on the developer's machine, before any message exists.
  • Payload size: each Avro message carries a short schema ID, not the full schema or repeated field names. This is the main reason payloads shrink.

What it shows. This is a constructed example, not a report of a real incident. It shows the mechanism: the schema turns a silent downstream data error into a loud failure at the producer, where it is cheapest to fix.

Sources: MuleSoft docs: Schema Registry replaces the embedded schema with an ID

Illustrative example

A Friday rename, and the safe way to do it

  • The rename: a producer changes user_id to customer_id in a JSON event and deploys. Kafka does not validate content and the JSON still parses, so there are no errors. Downstream billing and analytics start reading nulls.
  • Why it breaks: Kafka has no idea anything was "renamed". Consumers see one field vanish and another appear, which is a delete plus an add. Both are breaking changes.
  • The safe path with a schema: add the new field as optional with a default. Ship consumers that read the new field and stop reading the old one. Only then remove the old field. The registry blocks the shortcut of deleting it in one step.

What it shows. This is a constructed example, not a report of a real incident. I looked for a public postmortem of a renamed field on a payments topic and did not find a verifiable one. The migration steps follow Conduktor's schema evolution guide.

Sources: Conduktor: Avro schema evolution and compatibility guide

Tradeoffs

  • One more service to run

    Schema Registry has to be operated.

  • Opaque messages

    Binary messages cannot be read in kafka-console-consumer without the Avro CLI, or Kafdrop with registry integration.

  • A learning curve

    The .avsc files and compatibility rules are new to engineers who have not used them.

Plain JSON is fine for

  • An internal event bus between two services
  • Contracts that are stable

Avro pays off for

  • Multiple producers and consumers
  • Audit requirements
  • High throughput

Final thought

Normal Kafka gives you a fast, durable message bus. Avro gives you a fast, durable, self-describing, contract-enforced message bus. In payments, where a field rename can cascade into a compliance incident, the contract enforcement alone is worth the operational overhead.

If this sounds familiar. If your team is still on JSON topics and schema drift has bitten you even once, it is time to make the switch.

Keep reading