CONCEPT Cited by 1 source
Component version migrate function¶
Definition¶
A component version migrate function is an explicit, per-component function — typically auto-generated as a stub but implemented by developers — that backports an instance of a newer major version of a component to the previous major version. It is the codified hook that keeps old clients working when a newer version of a component is live on the backend.
Callers: the serialisation runtime, when it determines the client cannot accept the newer version (see concepts/client-spec-version).
Canonical wiki instance (Yelp Konbini)¶
Konbini's example. Yelp wants to
change Button's text parameter from String to a custom
FormattedText supporting http links. This is
a breaking
change (version 0.8 → 1.0); older clients would receive a
type they can't decode. Konbini auto-generates an empty
migrate() method on CookbookButtonV1:
def migrate(model: CookbookButtonV1) -> CookbookButtonV0:
"""
The migrate function defined here is meant to backport an
instance of CookbookButtonV1 to an instance of
CookbookContainerV0. Its default behavior is to throw an
error signifying that backporting the model is not
supported. However, we highly recommend replacing this
behavior with your own custom logic ...
"""
return CookbookButtonV0(
text=model.text.toString(), # FormattedText -> String
style=model.style,
on_click=model.on_click,
size=model.size,
background_color=model.background_color,
)
Yelp: "This method is called whenever the spec version on the client is lower than the one on the backend. In that case, the backend tries to instantiate a CookbookButtonV1 class but it realizes the client only supports CookbookButtonV0."
Design properties¶
- Default is fail-safe. Generated default throws. If
developers forget to implement
migrate(), the backend errors loudly rather than silently sending an incompatible object; the CHAOS feature gets dropped via the feature error wrapper rather than crashing the view. - Explicit opt-out required. Choosing not to support
older clients for a given feature is an explicit act —
leaving
migrateat default-throws. Yelp's framing: "highly recommend replacing this behavior". - Field-level responsibility. Migration logic is
per-field. Converting
FormattedText → Stringis a.toString(); other conversions may need summarisation or data loss. The developer knows the domain; the codegen provides the plumbing. - Chain-free default. The post shows only
V1 → V0. It doesn't state whetherV2 → V0is expected to chain (V2 → V1 → V0via composed migrates) or be a separate pairwise function — a caveat worth watching.
When migrate functions don't apply¶
- Non-breaking additions. Adding a new optional parameter is non-breaking; no migrate needed. The field is absent on old clients; they ignore it.
- Enum additions. A new enum value is breaking only if
older clients would misinterpret it. Usually handled with
explicit
unknown-case mapping rather than a migrate. - Deprecations without type change. If a field is deprecated but still sent, migrate is unnecessary; it's just stale data.
Contrasts¶
- Protobuf / Thrift / Avro field compatibility — traditionally solved by "add fields, don't remove, reserve tags". Migrate functions are the richer escape hatch when type change is unavoidable.
- GraphQL directive-based field lifecycle — see patterns/directive-based-field-lifecycle. GraphQL deprecates fields; it does not provide a server-side per-client backport the way migrate does.
- API versioning (v1 vs v2 endpoints) — whole-endpoint versioning is coarser than per-component major-version migration; Konbini migrate is finer-grained.
Seen in¶
- sources/2026-04-22-yelp-how-yelp-keeps-server-driven-ui-consistent-across-four-platforms
— canonical wiki first source. Yelp Konbini auto-generates
migrate()stubs on every major-version bump; developers implement them to backport newer Cookbook component instances to previous major versions for older clients.