A database migration does not stop at the database when change data capture is present. DDL changes the connector's view of a table; the connector produces a revised event schema; a serializer and registry may accept or reject that revision; retained events preserve older shapes; and consumers deploy on independent schedules. CDC schema evolution is therefore a distributed contract migration. A change that is safe for SQL clients can still break a stream processor, materialized view, or replay job.
The safest approach separates storage evolution from event-contract evolution. Database owners remain responsible for transaction and application compatibility. The data platform owns reliable schema capture, serialization, registration, and replay. Producers own the meaning and rollout of published fields. Consumers own declared dependencies and timely upgrades. A review should follow one proposed DDL statement across all of those layers before it reaches production.
Map every schema boundary
Inventory the source table schema, connector envelope, key schema, value schema, registry subject or equivalent identifier, transport topic, transformations, sink schema, and consumer models. Include schema history used internally by the connector. Names and types can be altered by converters or single-message transforms, so a registry schema may not mirror SQL exactly. Capture logical types, nullability, defaults, precision, scale, field names, primary keys, and operation metadata at each boundary.
Declare which artifact is the consumer contract. Some teams expose the raw Debezium envelope; others publish a curated event after an outbox or normalization stage. Raw CDC is operationally rich but couples consumers to source tables and connector semantics. A curated contract adds a maintained transformation but can stabilize names, redact fields, and separate database refactoring from business events. Do not call both authoritative without defining precedence and lifecycle.
| Layer | Schema concern | Owner | Evidence before change |
|---|---|---|---|
| Database | DDL, defaults, constraints, key | Application and DBA | Migration compatibility test |
| Connector | Captured metadata and envelope | Data platform | Staging capture with exact version |
| Serialization | Logical types and field encoding | Data platform | Old/new reader-writer tests |
| Registry | Subject strategy and compatibility mode | Platform governance | Registration dry run |
| Consumer | Selected fields and semantics | Consumer team | Replay and deployment evidence |
Classify DDL by consumer effect
Adding a nullable field is often operationally easier than removing or renaming one, but no DDL category is universally safe. A consumer that rejects unknown JSON fields can fail on an addition. An Avro reader may require defaults depending on which schema reads existing data. Changing decimal precision, timestamp interpretation, enum domain, key, or nullability can alter meaning without an obvious parser error. Classify both structural compatibility and semantic compatibility.
Treat rename as add, migrate, and remove unless the whole chain provides proven alias semantics. Widening a database numeric type may map differently through a converter and sink. A primary-key change is especially risky because it can change partitioning, ordering, compaction identity, and upsert behavior. Table rename and topic-routing changes affect identity even when columns stay equal. Build a change catalog based on your actual serialization and consumers, not generic SQL folklore.
| Proposed change | Hidden CDC risk | Safer migration | Required test |
|---|---|---|---|
| Add column | Strict readers or missing historical value | Nullable/defaulted addition | Old reader consumes new event |
| Rename column | Appears as remove plus add | Dual fields with deprecation | Replay across both generations |
| Change type | Converter or sink coercion | New field and controlled backfill | Boundary and overflow cases |
| Change key | Partition and upsert identity changes | New topic or versioned key | Ordering, delete, and join tests |
| Drop column | Old consumers and replay depend on it | Usage proof then delayed removal | Oldest supported consumer test |
Test writer and reader schema resolution
Schema-aware formats resolve data using writer and reader schemas according to format rules. In Avro, field names, defaults, aliases, unions, and type promotion affect resolution; a database default is not automatically an Avro reader default. Generate events with the production connector, converter, and configuration rather than hand-writing a schema that merely looks equivalent. Store representative old and new records so compatibility tests exercise bytes and metadata, not just schema text.
Test all required directions. Backward compatibility asks whether a new reader can consume old data; forward compatibility asks whether an old reader can consume new data; full combines directions, and transitive modes extend checks through history. The correct policy depends on deployment and replay. A stream with long retention and independent consumers commonly needs stronger history-aware guarantees than a coordinated short-lived integration. Registry acceptance proves configured structural rules, not business meaning.
Make registry policy match deployment reality
Choose subject naming and compatibility mode deliberately. Topic, record, or custom strategies produce different sharing and evolution boundaries. Document whether key and value evolve independently, which team may register, and whether auto-registration is allowed in production. Prefer CI registration checks and controlled deployment over discovering incompatibility when a connector restarts. Protect the registry because deleting schema history can make retained events unreadable even though broker data still exists.
Version connector configuration, converters, transformations, and registry settings with the database migration. A converter upgrade can change schema representation without DDL. Run a canary connector or isolated topic when the change is material, but ensure it reads the same source change safely and does not alter source retention unexpectedly. Compare schema fingerprints and sample records before and after. Alert on unplanned schema registrations and incompatible attempts.
Roll consumers through expand and contract
Expand the event contract first. Add the new field or version while preserving the old representation, deploy consumers that can read both, then change producers to populate the new path. Measure use of the old field through declared dependencies, build metadata, or runtime telemetry. Only after all supported consumers and replay jobs have migrated should the old field be removed. Set a deprecation date and owner rather than leaving dual fields forever.
For incompatible keys, semantics, or identity, a versioned topic is often clearer than forcing one subject through a breaking transition. Dual-publish for a bounded period, reconcile outputs, migrate consumers, and retire the old topic after retention and recovery needs clear. Avoid consumer-specific branches of the same event; they multiply producer obligations. Provide one migration guide with exact old/new examples and handling for null, delete, snapshot, and replay records.
Design for replay across schema generations
A production fix may replay months of records written under several schemas. Test the current consumer against the oldest retained schema and representative intermediate versions. Ensure schema IDs remain resolvable, logical-type libraries are available, and defaults produce intended meaning. If a sink evolved destructively, replay into an isolated target and transform deliberately rather than writing old events into a schema that no longer represents them.
Snapshot records also need testing because a new initial or incremental snapshot uses the schema current at read time, while historical streaming records keep older writer schemas. Deletes and tombstones may carry different payload availability. A migration that relies on before values must account for database and connector configuration. Document exactly which fields can be absent by operation and version, then make consumers branch on contract evidence rather than exceptions.
Implement compatibility checks before merge
In CI, apply the proposed database migration to a representative source, run the pinned connector and converters, capture old and new events, and attempt registry registration under production policy. Execute consumer contract tests for every supported version. Add semantic assertions for units, timezone, precision, enum meaning, key identity, and delete behavior. A check should output the exact failing consumer and field, not a generic incompatible status.
Require an exception record when a breaking change is intentional: owner, affected consumers, migration plan, dual-run window, rollback, retention impact, and expiry. After deployment, watch connector schema-history errors, registration failures, deserialization errors, dead-letter volume, consumer lag, and sink rejects. Reconcile critical downstream tables. Close the change only when old representations and temporary routes are retired or explicitly supported.
Key takeaways
- Follow DDL through connector, converter, registry, transport, replay, and sink layers.
- Treat structural compatibility and semantic compatibility as separate tests.
- Generate schemas with the exact production connector path instead of approximating them.
- Use expand-and-contract or versioned topics for independently deployed consumers.
- Preserve registry history and test current readers against the full retained event history.
Frequently asked questions
Is adding a nullable database column always compatible?
No. It is usually easier, but strict readers, converter mappings, registry policy, historical defaults, or sink schemas can still fail. Test generated events against old readers and current replay requirements.
Does registry approval guarantee safety?
It guarantees only the configured schema-compatibility rules. It does not understand business meaning, key partitioning, consumer code outside registration, data quality, or operational rollout.
Should raw CDC be the public data contract?
It can be, when consumers accept source-table coupling and connector semantics. A curated event is preferable when database refactoring, redaction, stable business identity, or consumer-friendly evolution matters more than minimal latency.
Conclusion
CDC turns an ordinary database schema change into a multi-version event migration. Safe evolution requires a mapped contract, real generated records, directionally correct compatibility policy, coordinated consumer rollout, and replay proof. When teams test the whole chain before merge and retain evidence through retirement, database development can continue without surprising every downstream system.