Skip to content

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:

  1. An existing boolean config property has shipped and is in use by deployments.
  2. The property's semantics have grown — a new third state, or a distinction within one of the existing states, needs to be expressible.
  3. 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:

  1. Remove the boolean, ship the enum — breaks every existing deployment on upgrade. Nuclear option; unacceptable for widely-used frameworks.
  2. 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.
  3. 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

  1. Add the new enum property alongside the old boolean, not replacing it. The old boolean stays in the codebase.
  2. Define an auto-mapping table from the old boolean's values to equivalent enum values:
  3. flag = truemode = X
  4. flag = falsemode = Y
  5. On config load, prefer the new property if both are set; log a deprecation warning if the old boolean is used.
  6. Document both in the release notes, clearly marking the old as deprecated and pointing at the replacement.
  7. 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 boolean flush.lsn.source:
  • flush.lsn.source=truelsn.flush.mode=connector
  • flush.lsn.source=falselsn.flush.mode=manual
  • offset.mismatch.strategy (enum: no_validation, trust_offset, trust_slot, trust_greater_lsn) deprecates and replaces the boolean internal.slot.seek.to.known.offset.on.start:
  • …=falseno_validation
  • …=truetrust_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.

Seen in

  • sources/2025-12-18-zalando-contributing-to-debezium-fixing-logical-replication-at-scalecanonical 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.source boolean automatically maps to the new enum values: true maps to connector and false maps to manual. This gives users time to migrate to the new configuration during the deprecation period without breaking existing deployments."
Last updated · 428 distilled / 1,221 read