PATTERN Cited by 1 source
Backward-compatible config migration (boolean → enum)¶
Intent¶
When a boolean configuration property needs to grow into a richer enumerated type (three or more states), migrate forward with automatic mapping from the deprecated boolean to equivalent enum values, so existing deployments keep working unchanged during the deprecation window. Add the new enum, deprecate but don't remove the boolean, auto-map old values to new ones, document both, remove the boolean after a release or two.
Context¶
The pattern applies when:
- An existing boolean config property has shipped and is in use by deployments.
- The property's semantics have grown — a new third state, or a distinction within one of the existing states, needs to be expressible.
- The deprecation window must not break existing deployments — users who never update their config should keep getting the same behaviour.
Problem¶
Three wrong ways to handle the migration:
- Remove the boolean, ship the enum — breaks every existing deployment on upgrade. Nuclear option; unacceptable for widely-used frameworks.
- Keep the boolean, add another flag for the third state — two independent properties with correlated semantics ("if flag_a=true, flag_b must be false"). Semantics rot; operators get configuration combinations the framework author never tested.
- Add the enum, silently ignore the old boolean — quiet behaviour change on upgrade. Worse than option 1 because it fails silently instead of loudly.
Shape¶
- Add the new enum property alongside the old boolean, not replacing it. The old boolean stays in the codebase.
- Define an auto-mapping table from the old boolean's values to equivalent enum values:
flag = true→mode = Xflag = false→mode = Y- On config load, prefer the new property if both are set; log a deprecation warning if the old boolean is used.
- Document both in the release notes, clearly marking the old as deprecated and pointing at the replacement.
- Plan the removal — scheduled for a future major version, giving users at least one release's notice.
Examples on wiki¶
Debezium 3.4's two Zalando-contributed properties both instantiate the pattern:
lsn.flush.mode(enum:manual,connector,connector_and_driver) deprecates and replaces the booleanflush.lsn.source:flush.lsn.source=true→lsn.flush.mode=connectorflush.lsn.source=false→lsn.flush.mode=manual-
offset.mismatch.strategy(enum:no_validation,trust_offset,trust_slot,trust_greater_lsn) deprecates and replaces the booleaninternal.slot.seek.to.known.offset.on.start: …=false→no_validation…=true→trust_offset
Consequences¶
Upside:
- Existing deployments upgrade without config changes; same behaviour is preserved.
- Users get access to the richer enum states when they're ready to opt in.
- The deprecation becomes a discoverable signal via release notes and deprecation warnings rather than a silent behaviour change.
Downside:
- The codebase carries both the old and new properties for at least one release, doubling the surface area for the migration period.
- The auto-mapping is semantic, not cosmetic — if the framework author gets the mapping wrong, existing deployments get silently-wrong behaviour on upgrade.
- Documentation must cover both properties and the mapping, temporarily growing the config reference.
When not to apply¶
Don't use when the new enum has no natural match for either boolean value (the semantics genuinely changed, not grew). In that case a config-schema version bump with explicit migration is clearer than trying to force a mapping.
Related patterns on wiki¶
- patterns/schema-registry-backward-compat — schema-level backward-compat; the data-plane analogue of this config-plane pattern.
- patterns/spec-version-negotiation-for-backward-compat — version-negotiation protocol for API-level compat.
Seen in¶
- sources/2025-12-18-zalando-contributing-to-debezium-fixing-logical-replication-at-scale
— canonical wiki introduction. Zalando's two 2025-12
Debezium contributions both deprecate existing boolean
properties and introduce new enum properties with automatic
backward-compat mapping. The post frames the discipline
verbatim: "To ensure a smooth transition, we implemented
full backward compatibility where the deprecated
flush.lsn.sourceboolean automatically maps to the new enum values:truemaps toconnectorandfalsemaps tomanual. This gives users time to migrate to the new configuration during the deprecation period without breaking existing deployments."
Related¶
- patterns/opt-in-driver-level-lsn-flush — the pattern
lsn.flush.modeinstantiates; this pattern is how it ships without breaking existing deployments. - patterns/authoritative-slot-over-authoritative-offset
— the pattern
offset.mismatch.strategyinstantiates; same relationship. - concepts/lsn-flush-mode — canonical instance enum.
- concepts/offset-mismatch-strategy — canonical instance enum.
- systems/debezium — the framework where both contributions landed.