Backward compatibility preserves support for earlier contracts while a system evolves. For a replacement API or database interface, this usually means existing clients continue working with the updated implementation. For schema evolution, the direction is more specific: a new reader schema can read data written using an older writer schema. State which component changes and which remains unchanged before deciding whether a change is compatible.
Consider an event dataset that initially contains order_id and amount. A new application also needs currency. With Apache Avro, adding currency to the reader schema with an appropriate default allows the new reader to process historical records that do not contain that field. The default must follow Avro's schema rules and have a valid business meaning. Assuming every historical order used USD would produce incorrect results if the dataset actually contains multiple currencies.
Compatibility depends on the serialization format, reader implementation, and application contract. Adding an optional JSON property is often safe, but an older consumer that rejects unknown properties may still fail. Adding a nullable database column may preserve explicitly named queries while breaking positional inserts or applications that assume a fixed SELECT * result shape. Consequently, an additive change is a useful starting point, not a universal compatibility guarantee.
Distinguish backward compatibility from forward compatibility. A new reader processing old records demonstrates backward schema compatibility; an old reader processing new records demonstrates forward schema compatibility. Full compatibility requires both directions. During rolling deployments, old and new producers and consumers may overlap, so checking only backward compatibility may be insufficient. Replaying long-retained data can also require checking a proposed schema against multiple historical versions rather than only the latest version.
Cloud data platforms commonly apply this idea through schema registries, versioned datasets, transformation jobs, and compatibility views. A registry can reject schema changes that violate its configured compatibility rules. An ETL job can normalize historical representations into a stable analytical model. In a data lake, however, updating catalog metadata does not rewrite existing objects or guarantee that every partition can be read with the new definition.
For a disruptive database change, use an expand-and-contract migration. Add the new field without immediately removing the old one, deploy readers that tolerate the transition, backfill historical rows, and coordinate writes so both representations remain consistent where necessary. Remove the old field only after its consumers have migrated and the rollback window has closed.
Structural compatibility does not guarantee semantic compatibility. Changing an amount from dollars to cents, changing timestamp interpretation, or expanding identifier values can break calculations even when the declared type remains unchanged. Test historical samples, null handling, value ranges, precision, and business invariants. Compatibility reduces coordinated deployments and replay failures, but retaining old contracts adds testing, storage, and maintenance costs; explicit deprecation policies keep those costs bounded.