Setting Up Feature Flags
What you'll learn
- Generating the Feature Flag SDK with provider implementations
- Choosing between Firebase Remote Config and Flagr backends
- Using feature flags to gate functionality at runtime
- Setting up A/B testing and gradual rollouts
Prerequisites
- An existing Archipelago monorepo (see Monorepo Scaffolding)
- Firebase configured (if using Remote Config provider)
Step 1: Generate the Feature Flag SDK
bash
archipelago generate feature_flag_sdkYou will be prompted for:
- appName —
MyApp(must match your monorepo app name) - isForMonorepo —
true - includeRemoteConfig —
true(Firebase Remote Config provider) - includeFlagr —
false(Flagr provider, optional)
Or use a config file:
json
{
"appName": "MyApp",
"isForMonorepo": true,
"includeRemoteConfig": true,
"includeFlagr": false
}bash
archipelago generate feature_flag_sdk --config flags_config.jsonStep 2: Understand the Generated Structure
The Feature Flag SDK uses the API/Impl split for vendor-agnostic flag evaluation:
infrastructure/
├── feature_flag_sdk_api/
│ └── lib/src/
│ ├── feature_flag_client.dart # Abstract flag contract
│ ├── flag_value.dart # Typed flag value wrapper
│ └── flag_key.dart # Flag key definitions
└── feature_flag_sdk_impl/
└── lib/src/
├── remote_config_client.dart # Firebase Remote Config impl
├── flagr_client.dart # Flagr impl (if enabled)
├── local_flag_client.dart # Local overrides for dev
└── di/
└── feature_flag_module.dart # DI registrationStep 3: Define Flag Keys
Register your feature flags in the flag key definitions:
dart
// feature_flag_sdk_api/lib/src/flag_key.dart
abstract class FlagKey {
static const newCheckout = 'new_checkout_flow';
static const darkMode = 'dark_mode_enabled';
static const maxRetries = 'max_retry_count';
}Step 4: Evaluate Flags in Features
Features depend on feature_flag_sdk_api and query flags through the abstraction:
dart
final flags = getIt<FeatureFlagClient>();
// Boolean flags
if (await flags.getBool(FlagKey.newCheckout)) {
// Show new checkout flow
} else {
// Show legacy checkout
}
// Typed values
final maxRetries = await flags.getInt(FlagKey.maxRetries, defaultValue: 3);
// Listen to flag changes
flags.onValueChanged(FlagKey.darkMode).listen((enabled) {
themeController.setDarkMode(enabled);
});Step 5: Local Overrides for Development
Use the local flag client to override values during development without touching the remote backend:
dart
// In debug bootstrap
final localFlags = LocalFlagClient(overrides: {
FlagKey.newCheckout: true,
FlagKey.maxRetries: 5,
});
getIt.registerSingleton<FeatureFlagClient>(localFlags);Key Customization Points
| Customization | Where to Change |
|---|---|
| Add new flag provider | Create new FeatureFlagClient impl |
| Set default flag values | remote_config_client.dart — defaults map |
| Fetch interval | remote_config_client.dart — cache expiration |
| Add user targeting | Extend FeatureFlagClient with user context |
Next Steps
- Set up analytics to track flag-driven experiments
- Configure monitoring to alert on flag evaluation errors