Feature Flags

New

Ship features safely with gradual rollouts, A/B testing, and kill switches. Decouple deployment from release.

Instant Toggle

No deployment needed

Percentage Rollout

Gradual 1% → 100%

User Targeting

Rules-based segments

Edge Evaluation

<10ms latency

Overview

Feature flags let you deploy code without releasing features. Ship safely with gradual rollouts, target specific users, run A/B experiments, and instantly roll back if something goes wrong—all without redeploying.

Quick Start

Check a feature flag in your application:

import { platform } from '@/lib/platform'

// Check if feature is enabled for a user
const isEnabled = await platform.flags.isEnabled('new_checkout', {
  userId: user.id,
  // Optional context for targeting rules
  context: {
    email: user.email,
    plan: user.subscription?.plan,
    country: user.country,
  },
})

if (isEnabled) {
  // Show new checkout experience
  return <NewCheckout />
} else {
  // Show current checkout
  return <CurrentCheckout />
}

Creating Flags

Create and manage flags through the SDK or dashboard:

Create a flag
// Create a new feature flag (typically done via dashboard)
await platform.flags.create({
  key: 'new_pricing_page',
  name: 'New Pricing Page',
  description: 'Redesigned pricing page with comparison table',
  enabled: false, // Start disabled
  rolloutPercentage: 0,
  targeting: {
    rules: [
      {
        // Enable for internal team first
        conditions: [
          { field: 'email', operator: 'endsWith', value: '@sylphx.dev' }
        ],
        percentage: 100,
      },
    ],
  },
})

Dashboard Recommended

While you can create flags via API, we recommend using the dashboard for better visibility and audit trails.

Evaluation

Flags are evaluated based on multiple factors:

1. Kill Switch

If the flag is disabled globally, it returns false immediately.

2. Targeting Rules

Rules are evaluated in order. First matching rule determines the result.

3. Default Rollout

If no rules match, the default percentage rollout is applied.

Targeting Rules

Target specific users or segments with rules:

// Complex targeting example
const targeting = {
  rules: [
    // Rule 1: 100% for internal team
    {
      name: 'Internal Team',
      conditions: [
        { field: 'email', operator: 'endsWith', value: '@company.com' }
      ],
      percentage: 100,
    },
    // Rule 2: 50% for beta users
    {
      name: 'Beta Program',
      conditions: [
        { field: 'plan', operator: 'equals', value: 'beta' }
      ],
      percentage: 50,
    },
    // Rule 3: 10% for US users on paid plans
    {
      name: 'US Paid Users',
      conditions: [
        { field: 'country', operator: 'equals', value: 'US' },
        { field: 'plan', operator: 'in', value: ['pro', 'enterprise'] },
      ],
      percentage: 10,
    },
  ],
  // Default: 0% for everyone else
  defaultPercentage: 0,
}
OperatorDescriptionExample
equalsExact matchplan equals "pro"
inValue in arraycountry in ["US", "CA"]
containsString containsemail contains "@beta"
startsWithString prefixuserId startsWith "test_"
endsWithString suffixemail endsWith "@company.com"
gt / gte / lt / lteNumeric comparisonage gte 18
semverVersion comparisonappVersion semver ">=2.0.0"

Percentage Rollouts

Gradually roll out features to reduce risk:

// Start with 1% rollout
await platform.flags.update('new_feature', {
  enabled: true,
  rolloutPercentage: 1, // 1% of users
})

// If metrics look good, increase gradually
await platform.flags.update('new_feature', {
  rolloutPercentage: 10, // 10% of users
})

// Continue until 100%
await platform.flags.update('new_feature', {
  rolloutPercentage: 100, // All users
})

Sticky Bucketing

Users are bucketed consistently based on their ID. A user at 5% rollout will stay in the same bucket at 10%, 50%, etc.

JSON Config Flags

Use flags to return configuration values, not just booleans:

// Define a config flag
await platform.flags.create({
  key: 'checkout_config',
  type: 'json',
  defaultValue: {
    maxItems: 10,
    enableCoupons: true,
    paymentMethods: ['card', 'paypal'],
    theme: 'default',
  },
})

// Retrieve the config
const config = await platform.flags.getConfig('checkout_config', {
  userId: user.id,
})

// Use it in your app
const { maxItems, enableCoupons, paymentMethods } = config

React Integration

Hooks for seamless React integration:

import { useFeatureFlag } from '@sylphx/platform-sdk/react'

function PricingPage() {
  const { enabled, loading } = useFeatureFlag('new_pricing')

  if (loading) {
    return <PricingSkeleton />
  }

  return enabled ? <NewPricing /> : <CurrentPricing />
}

Best Practices

Use Descriptive Keys

Name flags clearly: new_checkout_flow, experiment_pricing_v2, enable_dark_mode

Clean Up Old Flags

Remove flags once features are fully rolled out to reduce complexity

Start Small

Begin with 1-5% rollout, monitor metrics, then increase gradually

Have a Rollback Plan

Document how to quickly disable a flag if something goes wrong

Log Flag Decisions

Track which variant users see for debugging and analytics

Test Both Paths

Ensure your code works correctly with the flag both on and off

Flag Types

Boolean

Simple on/off toggles

new_checkout_flow

Percentage

Gradual rollout (0-100%)

experiment_v2

User Segment

Target specific users

beta_users_only

JSON Config

Remote configuration

pricing_config

Use Cases

Gradual Rollouts

Release to 1% → 10% → 50% → 100% of users

A/B Testing

Compare variants with statistical analysis

Beta Programs

Enable features for specific user groups

Kill Switches

Instantly disable problematic features

Remote Config

Change behavior without deploys

Scheduled Launches

Time-based feature releases

API Reference

MethodDescription
flags.isEnabled(key, ctx)Check if a boolean flag is enabled
flags.getConfig(key, ctx)Get JSON config for a flag
flags.getAll(ctx)Get all flags for a user
flags.create(config)Create a new flag
flags.update(key, config)Update an existing flag
flags.delete(key)Delete a flag