Details of LaunchDarkly to ConfigCat Translation
This document discusses the details of how ConfigCat's "Import from LaunchDarkly" tool translates LaunchDarkly projects to ConfigCat products (i.e., how, in practice, the import tool converts the project data fetched fromLaunchDarkly's REST API to ConfigCat's Export/Import JSON format).
You need this information if you want to understand
- why the import tool produces the result that it does,
- what issues can arise during translation, and how to solve them,
- what the limitations of translation are.
Mapping between LaunchDarkly and ConfigCat entities
The table below shows how LaunchDarkly entities are mapped to ConfigCat entities.
LaunchDarkly entity | Corresponding ConfigCat entity | Notes |
---|---|---|
project | product | |
environment | environment | |
segment | segment | LaunchDarkly segments are specific to an environment, but ConfigCat segments are specific to a product, so mapped segment names are prefixed with the environment name to avoid ambiguity. |
feature flag | feature flag / setting | LaunchDarkly feature flags are directly contained by a project, but ConfigCat feature flags are organized into configs, so a config named "Main Config" is created to contain them. |
targeting toggle | - | No direct translation is possible. More on this here. |
prerequisites | - | Each prerequisite is translated to a Targeting Rule containing a Flag Condition. |
individual targets | - | Each target group is translated to a Targeting Rule containing an IS ONE OF User Condition. |
custom rule | Targeting Rule | Multiple clauses (i.e. AND conditions in ConfigCat's terminology) are not supported for segments, only for feature flags at the moment. |
custom rule clause | User Condition or Segment Condition | Some LaunchDarkly clauses cannot be translated to ConfigCat conditions with the same evaluation behavior, or at all. See also translation issues |
clause attribute reference | comparison attribute | LaunchDarkly context attribute paths don't always translate to ConfigCat user attribute names directly. See also this section. |
clause operator | comparator | Most LaunchDarkly operators have their counterparts in ConfigCat (there can be minor or major differences between them though), but a few operators are not supported by ConfigCat at all (e.g. "matches" / "does not match"). |
clause values | comparison value | As opposed to LaunchDarkly, not all counterparts of operators support multiple values. |
percentage rollout | Percentage Options | In LaunchDarkly, the basis of the grouping can be set for each percentage rollout, while in ConfigCat Percentage Evaluation Attribute can only be set at the feature flag level. |
default rule | trivial / fallback rule |
Mapping between LaunchDarkly contexts and ConfigCat User Objects
Both LaunchDarkly and ConfigCat support passing user and/or session-related contextual information to feature flag evaluation, which is essential for targeting: LaunchDarkly offers contexts, while ConfigCat offers User Objects for this purpose.
However, the data structure of these is different:
- In LaunchDarkly, in addition to the default user context, it is possible to define and use other, arbitrary contexts (e.g. device, application, etc.). Multi-contexts and nested objects are also possible.
- On the contrary, ConfigCat's User Object is a simpler data structure, primarily designed for storing user-related information. However, via custom attributes it's still able to store arbitrary information.
On top of that, LaunchDarkly context attributes are identified by the combination of a context kind and a path expression, while ConfigCat uses simple attribute names. For this reason, it is necessary to define an unambiguous mapping between the two.
This is done as shown in the following table:
LaunchDarkly context kind | LaunchDarkly context attribute path | Corresponding ConfigCat user attribute name |
---|---|---|
not specified or user | empty string or / | / |
not specified or user | key or /key | Identifier |
not specified or user | email or /email | Email |
not specified or user | country or /country | Country |
not specified or user | Identifier or /Identifier | /Identifier |
not specified or user | Email or /Email | /Email |
not specified or user | Country or /Country | /Country |
not specified or user | name or /name | name |
not specified or user | /address/city | /address/city |
device | empty string or / | device:/ |
device | name or /name | device:name |
organization | name or /name | organization:name |
organization | /address/city | organization:/address/city |
any | kind or /kind | /kind |
Please note that:
- Both LaunchDarkly context attribute paths and ConfigCat user attribute names are case-sensitive.
- In ConfigCat,
Identifier
,Email
andCountry
are predefined attributes. Everything else qualifies as custom attributes. - One-component LaunchDarkly attribute path expressions are always normalized to their unescaped form if possible. E.g.
/~0~1x
→~/x
, but/~1~00
→/~1~00
(as/~0
would be an ambiguous mapping). - Multi-component LaunchDarkly attribute path expressions are kept as is (unless they contain
:
characters - see below). - Context kinds other than
user
are included as a prefix in the mapped ConfigCat user attribute name, with:
as the separator. Because of this, LaunchDarkly context attribute paths containing:
characters needs to be escaped to avoid ambiguity. E.g.a:b
->/a~;b
,/a:b
->/a~;b
.
Translation issues
There are technical differences between LaunchDarkly and ConfigCat, therefore it's not always possible to translate all entities accurately, i.e. so that they are represented identically in ConfigCat, and provide equivalent behavior to the original. (By equivalent behaviour we primarily mean equivalent evaluation behaviour, i.e. that the evaluation of a feature flag or segment produces the same result for the same input parameters.)
Such problematic cases are called translation issues, and a severity level is assigned to them as follows.
🔴 HIGH - The imported entity cannot provide equivalent behavior to the original at all.
🟡 MEDIUM - The imported entity may not provide equivalent behavior to the original in every case.
🔵 LOW - The imported entity does not exactly reflect the original in some way, but it is expected to provide
equivalent behavior to the original.
The tables below show the possible translation issues.
Limitations
Usually these issues arise when you are on a lower plan, and hitting a subscription limit. If this prevents you from migrating to ConfigCat, feel free to contact us.
Code | Level | Issue | What can be the cause? | How is it handled? |
---|---|---|---|---|
L001 | 🔴 HIGH | The number of Targeting Rules resulting from the translation would exceed the subscription / technical limit. | There are too many rules in the original feature flag. | As many LaunchDarkly rules as the limit allows are imported, but the rest is omitted. |
L002 | 🔴 HIGH | The number of conditions resulting from the translation would exceed the subscription / technical limit. | There are too many clauses in a rule of the original feature flag. | As many LaunchDarkly clauses as the limit allows are imported, but the rest is omitted. |
L003 | 🔴 HIGH | The number of percentage options resulting from the translation would exceed the subscription / technical limit. | There are too many percentage rollout variations in the original feature flag. | As many LaunchDarkly percentage rollout variations as the limit allows are imported, but the rest is omitted. The percentage of the last imported item is adjusted so that the sum of percentages equals 100%. |
L004 | 🔴 HIGH | The length of a comparison value resulting from the translation would exceed the subscription / technical limit. | The value(s) of a LaunchDarkly clause translate to a string comparison value that would be too long. | The comparison value is truncated so that it fits within the limit. |
L005 | 🔴 HIGH | The number of items in a comparison value list resulting from the translation would exceed the subscription / technical limit. | The values of a clause translate to a comparison value list that would have too many items. | The comparison value list is truncated so that it fits within the limit. |
L006 | 🔴 HIGH | The length of an item in a comparison value list resulting from the translation would exceed the subscription / technical limit. | One or more values of a clause translate to a comparison value item that would be too long. | The comparison value item is truncated so that it fits within the limit. |
L007 | 🔴 HIGH | The length of a text setting value resulting from the translation would exceed the subscription / technical limit. | A feature flag variation value translates to a text setting value that would be too long. | The text setting value is truncated so that it fits within the limit. |
Technical differences
Code | Level | Issue | What can be the cause? | How is it handled? |
---|---|---|---|---|
T001 | 🔵 LOW | A project, environment, segment or feature flag was imported under a different name than the original. |
|
|
T002 | 🟡 MEDIUM | A feature flag was imported with a different key than the original. |
|
|
T003 | 🔵 LOW | A feature flag tag name was truncated. | LaunchDarkly may allow longer tag names than ConfigCat. | Names that are too long are truncated at the maximum length. If this results in a conflicting name, no effort is made to make it unique. |
T004 | 🔵 LOW | A JSON feature flag was encountered. | LaunchDarkly allows feature flags with JSON values, but ConfigCat doesn't support that directly at the moment. | A text setting is created in ConfigCat, with values containing the JSON variation values serialized to text. It is your responsibility to deserialize the text once returned by feature flag evaluation. |
T005 | 🟡 MEDIUM | A comparison attribute name was truncated. | A context attribute name is mapped to a user attribute name that is too long. | The comparison attribute name is truncated so that it fits within the limit. If this results in a conflicting name, no effort is made to make it unique. |
T006 | 🔴 HIGH | Unset off variation was encountered. | In LaunchDarkly, it is not required to set a variation for the case when targeting is turned off. In that case, feature flag evaluation will return the default value you pass to the LaunchDarkly SDK. There is no way to reproduce this behavior in ConfigCat. | There is no way to emulate this behavior in ConfigCat, so a placeholder value is used as follows:
|
T007 | 🔵 LOW | Targeting is turned off, and the targeting toggle was respected. | Targeting Toggle Translation Mode option was set to "Respect targeting toggle and don't import rules", and
| A single Targeting Rule that returns the off variation is created in ConfigCat, and the actual rules are not imported for the specific environment. (The imported feature flag will work as it does in LaunchDarkly at the time of import.) |
T008 | 🟡 MEDIUM | Targeting is turned off, and the targeting toggle was ignored. | Targeting Toggle Translation Mode option was set to "Ignore targeting toggle and import rules anyway", and
| The off variation is ignored, and the actual rules are imported for the specific environment. (The imported feature flag will not work as it does in LaunchDarkly at the time of import.) |
T009 | 🔴 HIGH | A segment clause references multiple segments, but cannot be translated due to subscription / technical limit. | ConfigCat doesn't support referencing multiple segments in Segment Conditions. There is a workaround though: non-negated LaunchDarkly clauses can be expanded into multiple ConfigCat Targeting Rules, negated LaunchDarkly clauses can be expanded into multiple ConfigCat conditions. However, in the specific case the expansion is not possible because of subscription / technical limits. | A Segment Condition is created in ConfigCat but it references the first segment only. The rest of the segment references are omitted. |
T010 | 🔴 HIGH | A segment that references another segment was encountered. | ConfigCat segments do not support targeting segments. | A placeholder condition is created in ConfigCat. |
T011 | 🔴 HIGH | An untranslatable clause was encountered in a feature flag or segment rule. | The LaunchDarkly clause is not translatable to a ConfigCat condition, not even via a workaround. Such cases are:
| A placeholder condition is created in ConfigCat. |
T012 | 🔵 LOW | A clause was translated to multiple Targeting Rules or conditions. | Some LaunchDarkly clauses like segment clauses referencing multiple segments cannot be directly translated to a single ConfigCat condition. However, in the specific case, a workaround that provides logically equivalent evaluation behavior is possible. | If the LaunchDarkly clause is non-negated, it is expanded into multiple ConfigCat Targeting Rules, otherwise it is expanded into multiple ConfigCat conditions. |
T013 | 🔴 HIGH | A "contains" / "does not contain" segment clause with multiple values was encountered. | In segments, the ConfigCat counterparts of the "contains" / "does not contain" operators only accept a single comparison value at the moment. | The clause is translated to a CONTAINS / DOES NOT CONTAIN segment, however only the first clause value is preserved. The rest of the values are omitted. |
T014 | 🔵 LOW | A "<", "<=", ">", ">=", "SemVer <", "SemVer <=", "SemVer >", "SemVer >=" or "before" / "after" clause with multiple values was encountered. | The ConfigCat counterpart of these operators allows a single comparison value only. | Multiple comparison values are reduced to a single one. (This can be done in such a way that the clause remains
logically accurate.) The rest of the values are omitted though. |
T015 | 🟡 MEDIUM | A "Context kind is (not) one of" clause was encountered. | In ConfigCat, there is no such concept as contexts and context kinds. ConfigCat SDKs won't automatically provide context kinds as an attribute via the User Object. | An ARRAY IS (NOT) ONE OF condition is created in ConfigCat, but it is your responsibility to pass the context
kind values to the ConfigCat SDK via the custom user attribute named |
T016 | 🟡 MEDIUM | A mobile targeting-related clause was encountered. | For mobile apps, LaunchDarkly allows targeting special,
automatically provided context attributes
of context kinds | The clause is translated, but it is your responsibility to pass the attribute values to the ConfigCat SDK via custom user attributes. |
T017 | 🟡 MEDIUM | A not accurately translatable "is (not) one of" clause was encountered. | In LaunchDarkly, "is (not) one of" clauses can work with string, boolean and number values, but their ConfigCat counterparts can work with strings only. This can be a problem in two cases:
| An IS (NOT) ONE OF condition is created in ConfigCat and the non-string values are converted to string. |
T018 | 🔵 LOW | One or more variations of a percentage rollout had to be omitted. | LaunchDarkly includes all the feature flag variations in a percentage rollout even if most of them are set 0%. However, this could lead to exceeding the subscription limit on Percentage Options in ConfigCat (especially, on lower plans). | As variations set to 0% don't affect the evaluation of the imported Percentage Options, translation omits as many of them as needed to fit within the limit. |
T019 | 🟡 MEDIUM | One or more percentage values of a percentage rollout had to be adjusted. | As opposed to LaunchDarkly, ConfigCat doesn't allow fractional percentage values in Percentage Options. | Non-integer percentage values are rounded. This may also cause the sum of the percentage values to over or undershoot 100%. In such cases, further adjustments are performed to make the sum exactly 100%. |
T020 | 🔴 HIGH | There are multiple percentage rollout rules in the feature flag, but they do not use the same attribute as the basis of the rollout. | In LaunchDarkly, it is possible to set different attributes as the basis of the rollout for each percentage rollout rule. In ConfigCat, this can only be set at the feature flag level. | There is no workaround. The attribute that occurs the most times is set as the flag's Percentage Evaluation Attribute. |
T021 | 🔴 HIGH | A segment with no rules was encountered. | LaunchDarkly allows segments to have no rules, while ConfigCat segments specify exactly one rule. | A segment with a placeholder condition is created in ConfigCat. |
T022 | 🔴 HIGH | A segment with multiple rules was encountered. | LaunchDarkly allows segments to have multiple rules, while ConfigCat segments specify exactly one rule. | A segment is created in ConfigCat, with a translation of the first rule only. The rest of the rules are omitted. |
T023 | 🔴 HIGH | A segment rule with multiple clauses was encountered. | LaunchDarkly allows multiple clauses in segment rules, while ConfigCat doesn't support AND conditions in segments at the moment. | There is no workaround. Clauses except for the first one are omitted. |
T024 | 🔴 HIGH | A segment rule with percentage targeting was encountered. | LaunchDarkly allows segment rules to include a percentage of targets only. ConfigCat segments doesn't offer such feature. | There is no workaround. The percentage targeting part is ignored. |
T025 | 🔴 HIGH | A segment rule was only partially translated. | Translating the segment rule would require multiple rules in ConfigCat, which is not supported. | The segment rule is only partially imported. |
T026 | 🔴 HIGH | A big segment was encountered. | Big segments are not supported by ConfigCat. | A normal segment with a hint about the issue is created in ConfigCat. |
T027 | 🔴 HIGH | Comparison value list item contains comma. | In the case of segments, multiple clause values translate to a comma separated comparison value list. There is no way to escape the comma, so it must be replaced with another character, otherwise values containing a comma would be interpreted as multiple items. | Comma is replaced with semicolon in comparison value list items. |
Data consistency
Code | Level | Issue | What can be the cause? | How is it handled? |
---|---|---|---|---|
D001 | 🔴 HIGH | The data model fetched from LaunchDarkly contains invalid, inconsistent or unexpected data. | In theory, such a thing cannot happen, but in practice it cannot be excluded. | Obviously, the import tool cannot produce a correct result from an inherently incorrect input. As a best effort, it generates a valid import model so that the import operation can go through, and you can review and fix the problematic entities. |
D002 | 🟡 MEDIUM | The feature flag was modified in LaunchDarkly while the feature flag data was being fetched. | Due to the peculiarities of the LaunchDarkly REST API, the full data model of a feature flag can only be queried for a single environment per a single request. So, it may happen that some non-environment-related properties of the feature flag are modified while fetching the feature flag data (e.g. name, variations, etc.) In such cases, inconsistencies across environments are possible in the retrieved data. | The import tool can only detect inconsistencies, but cannot do anything about them. Please check whether the imported feature flag is set correctly in each environment. Alternatively, you may try to re-import the specific feature flag. |
Further technical differences
- As opposed to LaunchDarkly, ConfigCat distinguishes between integer and decimal number feature flags. Therefore, when translating number feature flags, the ConfigCat setting type is guessed based on the variation values specified at the time of the import.
- For percentage rollouts, LaunchDarkly and ConfigCat use different algorithms to split users into groups. That is, even if the percentage values are the same, the distribution of users will be different. In other words, stickiness of percentage rollouts cannot be transferred to ConfigCat.
- In the case of percentage rollouts within custom rules, evaluation behavior is different between the two services when
the attribute used as the basis of the percentage rollout is not provided (i.e. not passed to the SDK on evaluation):
- LaunchDarkly will serve the value of the first variation whose percentage value is not 0%.
- ConfigCat will skip the targeting rule and continue evaluation with the next rule.
- In LaunchDarkly, all clause operators can work with context attribute value lists. In ConfigCat, most of the comparators (counterparts of operators) can work with a single user attribute only. The only exceptions is ARRAY IS (NOT) ONE OF.
- In LaunchDarkly, it is possible to control whether or not specific feature flags are visible to mobile and/or client-side SDKs (Client-side SDK availability). There is no such feature in ConfigCat, so this preference is ignored. All the feature flags are imported into a single config which can be accessed by all kinds of ConfigCat SDKs.
- In LaunchDarkly, it is possible to mark a feature flag as temporary or permanent. There is no such feature in ConfigCat. Yet translation preserves this piece of information by adding a tag to the feature flag.
- In LaunchDarkly, it is possible to assign a name to the variations (possible outcomes of the feature flag). There is no such feature in ConfigCat at the moment, so these pieces of information are not transferred.