This epic defines implementation for project-level export and import.
Docs PR: #7114
Feature flags
project_import_export_identity_overrides — gates the "Include identity overrides" toggle in
the export UI. Disabled by default. Enabled when the identity override import sub-issue lands.
Export format schema
The project export is a JSON object, vs. the env-level export which is a JSON array.
Entity field names match the OpenAPI spec exactly. The structural nesting mirrors the API. Features and segments are project-level definitions; environments hold the per-environment state. This avoids inventing export-only structural concepts.
Example
{
"version": 1,
"exported_at": "2026-04-02T18:00:00Z",
"tags": [
{
"label": "core",
"color": "#FF0000",
"description": "Core features",
"is_permanent": false
}
],
"segments": [
{
"name": "beta_users",
"description": "Beta programme users",
"rules": [
{
"type": "ALL",
"rules": [],
"conditions": [
{
"property_": "is_beta",
"operator": "EQUAL",
"value": "true"
}
]
}
]
}
],
"features": [
{
"name": "my_feature",
"default_enabled": true,
"is_server_key_only": false,
"initial_value": "default_value",
"description": "",
"tags": ["core"],
"multivariate_options": [
{
"type": "unicode",
"string_value": "variant_a",
"default_percentage_allocation": 33.33
}
]
}
],
"environments": [
{
"name": "Production",
"description": "Production environment",
"minimum_change_request_approvals": 2,
"allow_client_traits": true,
"banner_text": null,
"banner_colour": null,
"hide_disabled_flags": null,
"use_identity_composite_key_for_hashing": true,
"hide_sensitive_data": false,
"use_v2_feature_versioning": true,
"use_identity_overrides_in_local_eval": true,
"feature_states": [
{
"feature": "my_feature",
"enabled": true,
"feature_state_value": {
"type": "unicode",
"string_value": "prod_value"
},
"multivariate_feature_state_values": [
{
"multivariate_feature_option": 0,
"percentage_allocation": 50
}
]
}
],
"feature_segments": [
{
"feature": "my_feature",
"segment": "beta_users",
"priority": 0,
"feature_state": {
"enabled": true,
"feature_state_value": {
"type": "unicode",
"string_value": "beta_value"
},
"multivariate_feature_state_values": []
}
}
],
"identity_overrides": [
{
"identifier": "user123",
"feature": "my_feature",
"enabled": true,
"feature_state_value": {
"type": "unicode",
"string_value": "custom_value"
}
}
]
},
{
"name": "Staging",
"feature_states": [],
"feature_segments": []
}
]
}
Key design decisions
- All cross-references use names (environment name, segment name, tag label, feature name) — not IDs, so exports are portable across instances.
multivariate_feature_option in multivariate_feature_state_values is an index into the feature's multivariate_options array. In the API this is an integer FK; we reuse the field name but the semantics differ because IDs aren't portable. This is the only unavoidable divergence from the API.
version: 1 allows future schema evolution.
identity_overrides per environment is optional (only present when the user opts in).
tags is top-level and optional.
Matching on import (by name)
- Features: matched by
name (already unique per project via DB constraint).
- Segments: matched by
name. If duplicates exist in the target project, the first match is used. If duplicates exist in the export, all are imported.
- Tags: matched by
label. Same duplicate policy as segments.
- Environments: matched by
name. Missing environments are created with settings from the export. For existing environments: SKIP leaves settings unchanged, OVERWRITE_DESTRUCTIVE updates settings to match the export.
This epic defines implementation for project-level export and import.
Docs PR: #7114
Feature flags
project_import_export_identity_overrides— gates the "Include identity overrides" toggle inthe export UI. Disabled by default. Enabled when the identity override import sub-issue lands.
Export format schema
The project export is a JSON object, vs. the env-level export which is a JSON array.
Entity field names match the OpenAPI spec exactly. The structural nesting mirrors the API. Features and segments are project-level definitions; environments hold the per-environment state. This avoids inventing export-only structural concepts.
Example
{ "version": 1, "exported_at": "2026-04-02T18:00:00Z", "tags": [ { "label": "core", "color": "#FF0000", "description": "Core features", "is_permanent": false } ], "segments": [ { "name": "beta_users", "description": "Beta programme users", "rules": [ { "type": "ALL", "rules": [], "conditions": [ { "property_": "is_beta", "operator": "EQUAL", "value": "true" } ] } ] } ], "features": [ { "name": "my_feature", "default_enabled": true, "is_server_key_only": false, "initial_value": "default_value", "description": "", "tags": ["core"], "multivariate_options": [ { "type": "unicode", "string_value": "variant_a", "default_percentage_allocation": 33.33 } ] } ], "environments": [ { "name": "Production", "description": "Production environment", "minimum_change_request_approvals": 2, "allow_client_traits": true, "banner_text": null, "banner_colour": null, "hide_disabled_flags": null, "use_identity_composite_key_for_hashing": true, "hide_sensitive_data": false, "use_v2_feature_versioning": true, "use_identity_overrides_in_local_eval": true, "feature_states": [ { "feature": "my_feature", "enabled": true, "feature_state_value": { "type": "unicode", "string_value": "prod_value" }, "multivariate_feature_state_values": [ { "multivariate_feature_option": 0, "percentage_allocation": 50 } ] } ], "feature_segments": [ { "feature": "my_feature", "segment": "beta_users", "priority": 0, "feature_state": { "enabled": true, "feature_state_value": { "type": "unicode", "string_value": "beta_value" }, "multivariate_feature_state_values": [] } } ], "identity_overrides": [ { "identifier": "user123", "feature": "my_feature", "enabled": true, "feature_state_value": { "type": "unicode", "string_value": "custom_value" } } ] }, { "name": "Staging", "feature_states": [], "feature_segments": [] } ] }Key design decisions
multivariate_feature_optioninmultivariate_feature_state_valuesis an index into the feature'smultivariate_optionsarray. In the API this is an integer FK; we reuse the field name but the semantics differ because IDs aren't portable. This is the only unavoidable divergence from the API.version: 1allows future schema evolution.identity_overridesper environment is optional (only present when the user opts in).tagsis top-level and optional.Matching on import (by name)
name(already unique per project via DB constraint).name. If duplicates exist in the target project, the first match is used. If duplicates exist in the export, all are imported.label. Same duplicate policy as segments.name. Missing environments are created with settings from the export. For existing environments: SKIP leaves settings unchanged, OVERWRITE_DESTRUCTIVE updates settings to match the export.