Library
12 min read

Backward vs forward compatibility

The orders team adds a required currency field to the OrderPlaced event and deploys. The payments consumer, which nobody has touched in a month, starts failing on every message, because its schema says currency does not exist and its parser rejects unknown fields. The fix is fast. Then the analytics job replays last week's events to rebuild a report, and the new orders code fails on every old message, because those have no currency at all.

Both outages are the same mistake from opposite ends. Data written by one version of the code is read by another, in both directions, and for longer than anyone expects: events sit in Kafka for days and in the warehouse for years, mobile apps stay installed for months without updating, and a rolling deploy runs two versions side by side. Compatibility is the set of rules that keeps those readers and writers working when they disagree about the shape of the data.

Your answer

Your Android app talks to a JSON API. Twenty percent of users are on an app version from eight months ago. You want to rename the response field 'price' to 'amount' and add a new required request field 'currency'. What breaks, for whom, and what would you do instead?

Two directions, two words#

The terms are confusing because they are named from the reader's point of view, and people mix them up constantly. Pin them to who is reading what:

  • Backward compatible: new readers can read old data. The new version of the consumer, or the new code, understands messages and rows written by the old version. This is what lets you replay old events or read old rows after an upgrade.
  • Forward compatible: old readers can read new data. The old version of the consumer, still running somewhere, understands messages written by the new version. This is what lets you upgrade producers before every consumer has caught up.
  • Full compatibility: both at once. Any version can read data from any other, so the deploy order stops mattering.

The practical consequence is deploy order. If your change is only backward compatible, upgrade the consumers first: they can read both shapes, and only then may producers start writing the new one. If it is only forward compatible, upgrade producers first. Getting this backwards is the most common way a "safe" change takes a pipeline down.