Feature Flags

Toggle features in your Flutter app without deploying a new build. Ship code behind flags, then enable it when you're ready.

How flags work

Feature flags are fetched as part of the bootstrap snapshot when the SDK initialises. They are cached locally and evaluated entirely client-side — no network call is made when you check a flag at runtime.

Flags are updated in the background on a configurable polling interval. Changes made in the dashboard reach your users within one polling cycle — default 60 seconds.

Zero latency evaluation

Flag checks are synchronous and local — Koolbase.flags['flag_name'] reads from the in-memory cache. There is no async overhead or network dependency at evaluation time.

Check a flag

lib/home_screen.dartDart
// Simple boolean check
final showNewUI = Koolbase.flags['new_checkout'] == true;

// In a widget
Widget build(BuildContext context) {
  if (Koolbase.flags['new_onboarding'] == true) {
    return const NewOnboardingFlow();
  }
  return const LegacyOnboardingFlow();
}

Get all flags

lib/flags.dartDart
// Get the full flag map
final flags = Koolbase.flags;

// Iterate all flags
flags.forEach((key, value) {
  print('$key: $value');
});

// Check with a default fallback
final isEnabled = Koolbase.flags['feature_name'] ?? false;

Percentage rollouts

From the dashboard, set a rollout percentage on any flag — e.g. 25% means only 25% of your users see the flag as enabled. Bucketing is deterministic based on a hash of the device identifier, so a user always gets the same result across sessions.

To gradually roll out a feature: start at 5%, monitor for errors, then increase to 25%, 50%, 100%. To roll back, set the flag to 0% or toggle it off.

Deterministic bucketing

The SDK uses SHA-256 to hash a combination of the device ID and flag key. This ensures a user is always in the same bucket — they won't see the feature flicker on and off between sessions.

Kill switch pattern

Wrap any risky feature in a flag so you can disable it instantly if something goes wrong in production — no hotfix or App Store submission required:

lib/payments.dartDart
// Wrap risky features in a flag
Future<void> processPayment(PaymentDetails details) async {
  if (Koolbase.flags['new_payment_flow'] != true) {
    // Fall back to the old flow
    return legacyProcessPayment(details);
  }

  // New payment flow
  return newProcessPayment(details);
}

Always provide a fallback

When wrapping a feature in a flag, always implement the fallback path. If the SDK fails to load (no network on first launch), flags default to their fallback values. Design your app to work correctly in both states.

Creating flags in the dashboard

1

Navigate to your project → Feature Flags

2

Click New Flag and enter a key name (e.g. new_checkout)

3

Set the default state (enabled/disabled)

4

Optionally set a rollout percentage (0–100%)

5

Add targeting rules if needed (by device, OS, or custom traits)

6

Save — changes propagate within one polling cycle