Migrating the Swift SDK for Featurevisor v4
- Minimal migration path
- Breaking changes
- Root condition reasonBreaking
- Datafile update resultBreaking
- Module callbacksBreaking
- Evaluation detailsBreaking
- Requirement model changesBreaking
- Language differences
- OpenFeature
- Migration checklist
Upgrade Swift applications to SDK 4.0.0 for Featurevisor v4 support.
Follow the shared migration order: prepare canonical prerequisite datafiles, upgrade consumers, then upgrade the project CLI. Before publishing new runtime fields, follow Adopt new syntax safely.
Convert Groups before upgrading
This SDK silently ignores legacy feature ranges, with no compatibility handling or warning. Convert Groups to flat list requirements while still on the previous compatible SDK and v3 CLI, then publish all datafiles, caches and bundled copies before upgrading. Unconverted files can change cohorts or enable features without a variation. Old cohorts are not guaranteed. Follow Groups removed.
Minimal migration path#
Most Swift application code remains unchanged. These APIs were already available in the previous SDK line:
createFeaturevisor(...)andFeaturevisorOptionsisEnabled(...),getVariation(...), and feature variable getters- global variable getters using a single variable key
evaluateFlag(...),evaluateVariation(...), andevaluateVariable(...)stickyFeatures,stickyVariables,setStickyFeatures(...), andsetStickyVariables(...)getFeatureEvaluations(...),getVariableEvaluations(...), and child instancessticky_features_setandsticky_variables_setevents
If an application already uses canonical module callbacks and does not inspect legacy evaluation properties or construct old requirement model types, its source migration can be limited to selecting a compatible package release and testing its datafiles.
See the Swift SDK guide for the complete current API.
Breaking changes#
Root condition reason Breaking#
An unmet root gate reports conditions_unmet for feature flags and global variables, replacing the v3 required reason for feature flags and required_features_unmet for global variables. This applies to attribute, segment, feature and variable leaves in root conditions. Update callbacks, analytics and test expectations. Variation and feature variable evaluations retain their disabled reasons. See the shared migration guidance.
let unmetRequirement = evaluation.reason == .requiredlet unmetRequirement = evaluation.reason == .conditionsUnmetDatafile update result Breaking#
setDatafile now returns true when it accepts the update, including unchanged content, and false when it rejects the update or the instance is closed. A rejected update keeps the previous datafile and reports details through diagnostics. Calls that ignore the result keep working. Update any wrapper or interface that declares the old return type. Merging remains the default.
f.setDatafile(datafile)let accepted = f.setDatafile(datafile)if !accepted { print("Datafile rejected. Check diagnostics.")}Module callbacks Breaking#
The deprecated feature only before and after initializer arguments are removed. beforeEvaluation and afterEvaluation were already available in the previous SDK line, so this source change can be made before the breaking upgrade.
let module = FeaturevisorModule( name: "context", before: { options in options }, bucketValue: { $0.bucketValue }, after: { evaluation, _ in evaluation })let f = createFeaturevisor(FeaturevisorOptions(datafile: datafile, modules: [module]))let module = FeaturevisorModule( name: "context", beforeEvaluation: { options in options }, bucketValue: { $0.bucketValue }, afterEvaluation: { evaluation, _ in evaluation })let f = createFeaturevisor(FeaturevisorOptions(datafile: datafile, modules: [module]))The canonical callbacks run for feature and global variable evaluations, including prerequisite evaluations. If callback behaviour is specific to features, inspect options.featureKey before applying it. setup, bucketKey, bucketValue, and close are unchanged.
Evaluation details Breaking#
The legacy required and sticky properties are removed from Evaluation:
let evaluation = f.evaluateVariable("checkout", "colour")let prerequisites = evaluation.requiredlet sticky = evaluation.stickylet evaluation = f.evaluateVariable("checkout", "colour")let prerequisites = evaluation.conditionslet sticky = evaluation.stickyFeatureCheck evaluation.reason == .sticky to identify sticky results. stickyFeature is optional detail and is not present for every sticky evaluation.
Accumulating global variable evaluations add variableOverridePaths, which records every matched authored path in execution order. The existing singular override properties identify the final match. Failed evaluated variable prerequisites use the new .conditionsUnmet reason.
Requirement model changes Breaking#
The old runtime datafile model represented legacy required entries with RequiredValue and RequiredWithVariation. Both types are removed.
| Previous model | After migration |
|---|---|
RequiredValue.key(featureKey) | RequiredFeature.feature(featureKey) |
RequiredValue.withVariation(...) and RequiredWithVariation | No direct construction replacement. Author { feature, variation } under conditions and decode the generated datafile |
Use the unified conditions grammar for all leaf kinds and groups. Applications that decode CLI generated datafiles do not need to construct prerequisite expression models themselves.
Language differences#
Check bundled datafiles and deployment targets across Apple platforms before selecting the compatible package. The OpenFeature package minimums are described below.
OpenFeature #
FeaturevisorOpenFeature is a separate product in the featurevisor-swift2 package. Set the package requirement to from: "4.0.0" and use the matching Featurevisor and FeaturevisorOpenFeature products.
The provider initializer and key mapping remain unchanged, but its OpenFeature Swift SDK dependency moves from 0.5 to 0.7, resolving to 0.7.0. The provider implements the status and event API introduced in 0.6, including ProviderStatusTracker, and returns Future<Void, Never> from lifecycle methods. Test provider readiness, invalid datafile status, recovery, configuration changes and shutdown through OpenFeature after upgrading. The updated provider maps .conditionsUnmet to OpenFeature's disabled reason.
Swift's upstream evaluation context returns the same empty string for an omitted targeting key and an explicit empty key. The provider cannot tell them apart and must preserve an existing userId or configured field on omission. To request an empty field, set that field itself to "" in context attributes. Clear any inherited nonempty targeting key at its source first.
Reason strings#
OpenFeature 0.7 changes Reason raw values to specification strings. Update string comparisons, stored reasons and test expectations. Enum cases such as .targetingMatch and .error keep their names.
Reason.targetingMatch.rawValue // "targetingMatch"Reason.error.rawValue // "error"Reason.targetingMatch.rawValue // "TARGETING_MATCH"Reason.error.rawValue // "ERROR"Logging#
OpenFeature logging APIs now accept (any OpenFeatureLogger)? instead of Logging.Logger. This includes setLogger, FlagEvaluationOptions(logger:), MultiProvider(logger:) and logger parameters in custom provider evaluation methods. Use your own OpenFeatureLogger implementation or add the optional OpenFeatureSwiftLog product and wrap a swift-log logger with SwiftLogLogger.
import Loggingimport OpenFeaturelet logger = Logger(label: "checkout")OpenFeatureAPI.shared.setLogger(logger)import Loggingimport OpenFeatureimport OpenFeatureSwiftLoglet logger = Logger(label: "checkout")OpenFeatureAPI.shared.setLogger(SwiftLogLogger(logger))Package installation#
OpenFeature 0.7 removes upstream CocoaPods support. Featurevisor already uses Swift Package Manager and does not ship a podspec. Keep using the Featurevisor and FeaturevisorOpenFeature products above.
The package needs Swift 6.1 or later, which Xcode 16.3 and later include. Upgrade Xcode before the package if your applications or CI still build with an earlier release.
The package minimums rise to iOS 15, macOS 12, tvOS 15, and watchOS 8. These minimums apply even when an application selects only the core Featurevisor product. Core does not link OpenFeature, but Swift Package Manager still resolves the package dependency. Check every application and test target's deployment setting before selecting the new package release.
See Swift OpenFeature usage and the shared OpenFeature provider guide.
Migration checklist#
Required for the migration#
- Prepare and deploy canonical
conditionsdatafiles before changing the runtime. - Replace module
beforeandafterarguments with the canonical evaluation callbacks. - Replace legacy evaluation properties and remove old requirement model usage.
- Update both Featurevisor package products together when used.
- Build with Swift 6.1 or later, and check the raised package platform minimums and the OpenFeature 0.7 reason strings, logging and provider lifecycle.
- Test feature, variation, feature variable, global variable, sticky, child, module, and bundled fallback behaviour.
- Upgrade the project CLI last, review mutation order and date and regex comparisons, and retain a compatible rollback datafile.
Only if adopting optional features#
Follow Adopt new syntax safely before publishing new datafile syntax. Upgrade every CLI runner before adding checks or scenarios.

