Skip to main content

Feature Flags

Feature flags allow you to enable or disable features at runtime without deploying new code. This is essential for testing in production, incremental rollouts, and quick fixes.

How Feature Flags Work

Feature flags can be enabled at different scopes:
ScopeDescriptionUse Case
EnvironmentAll requests in that environmentTesting in sandbox/staging
CustomerAll requests for a specific customerBeta testing with select customers
UserRequests from a specific userInternal testing

Checking Feature Flags

Backend

from server.apps.feature_flags.public.constants import FeatureFlagNameEnum

# In any function with RequestCtx
if ctx.feature_flag_enabled(FeatureFlagNameEnum.MY_FEATURE):
    # New behavior
    pass
else:
    # Old behavior
    pass

Frontend

import { useFeatureFlagActive } from '@/hooks/useFeatureFlags';
import { FeatureFlagNameEnum } from '@/api/types';

function MyComponent() {
  const isMyFeatureEnabled = useFeatureFlagActive(FeatureFlagNameEnum.MY_FEATURE);
  
  if (isMyFeatureEnabled) {
    return <NewFeature />;
  }
  return <OldFeature />;
}

Request Lifecycle

Feature flags are loaded at the start of every request: The ContextMiddleware determines active flags by checking:
  1. User making the request
  2. Customer the request is for
  3. Environment-level settings

Adding a Feature Flag

1

Add to enum

Update FeatureFlagNameEnum:
class FeatureFlagNameEnum(StrEnum):
    MY_NEW_FEATURE = "my_new_feature"
2

Add to i18n

Add the flag to en.json for auditing:
{
  "feature_flags": {
    "my_new_feature": "My New Feature"
  }
}
3

Generate migration

just makemigrations
4

Update migration

Manually add a data migration to create the flag record:
def create_feature_flag(apps, schema_editor):
    FeatureFlag = apps.get_model("feature_flags", "FeatureFlag")
    FeatureFlag.objects.create(
        name="my_new_feature",
        description="Description of my new feature",
        is_active=False,
    )
5

Update OpenAPI schema

just codegen schemas
See this PR for a complete example of adding a feature flag.

Using a Feature Flag

Consider the scope needed:
Enable for all users in sandbox/staging first:
  1. Go to feature flags admin
  2. Enable for the environment
  3. Test thoroughly
  4. Promote to next environment

Removing a Feature Flag

When a feature is fully rolled out:
1

Verify rollout

Ensure the flag is enabled across all environments including production.
2

Confirm with product

Get approval that the feature is stable and can be permanent.
3

Remove from code

Remove all feature_flag_enabled checks and the enum entry.
4

Generate migration

Create a migration to remove the flag from the database.
5

Update schema

just codegen schemas
See this PR for a complete example of removing a feature flag.

Models

class FeatureFlag(TimeStampedModel):
    """The feature flag itself."""
    name = models.CharField(unique=True)
    description = models.TextField()
    is_active = models.BooleanField(default=False)


class FeatureFlagOverride(CustomerTimeStampedModel):
    """Override for specific user or customer."""
    feature_flag = models.ForeignKey(FeatureFlag)
    user = models.ForeignKey(User, null=True)
    customer = models.ForeignKey(Customer, null=True)
    is_active = models.BooleanField()
    
    class Meta:
        constraints = [
            # Exactly one of user or customer must be set
            require_exactly_one_non_null_constraint(
                fields=["user", "customer"],
                name="exactly_one_override_target",
            ),
        ]

Best Practices

Feature flags should be temporary:
  • Add flag when starting feature
  • Remove flag after full rollout
  • Don’t accumulate old flags
# Good
ENHANCED_WATERFALL_CALCULATION = "enhanced_waterfall_calculation"

# Bad
FLAG_123 = "flag_123"
NEW_FEATURE = "new_feature"
When a flag exists, test:
  • Flag enabled behavior
  • Flag disabled behavior
  • Transition between states
Add clear descriptions so anyone can understand:
  • What the flag controls
  • Why it was added
  • When it can be removed

Next Steps