Best Practices
Guidelines for using feature flags effectively and avoiding common pitfalls.
Flag lifecycle
Follow a clear lifecycle for each flag: Create → Roll out → Monitor → Clean up / archive.
- Create — Define the flag with a clear key and type (boolean or JSON)
- Roll out — Start with internal users, then beta, then gradual percentage ramp (see Release workflow)
- Monitor — Use the Overview tab to track exposure and behavior
- Clean up — Remove or archive flags once the feature is fully rolled out and stable
Leaving old flags in place causes confusion and drift. Archive or delete them when no longer needed.
Test before ramp
Use the SDK Toolbar locally to validate variants before changing production targeting rules. Override flag values in development, test both enabled and disabled states, then configure rollout rules in the dashboard once confident.
Remote config
For JSON flags, do not store secrets (API keys, passwords) in remote config — manage those with proper secret management tools. Use stable, descriptive keys for config values so targeting rules stay maintainable.
Feature Flag Naming
Use Descriptive Names
// ✅ Good naming
'new-checkout-flow'
'beta-features'
'admin-panel-v2'
'pricing-page-redesign'
// ❌ Avoid
'flag1'
'new-feature'
'test-flag'
'feature-123'Use Consistent Patterns
// ✅ Group related flags with prefixes
'checkout.new-flow'
'checkout.express-payment'
'checkout.guest-checkout'
// ✅ Use prefixes for different types
'landing.new-hero-section'
'config.max-retries' // Configuration
'beta.new-features' // Beta features
// ✅ Use versions for flags that are updated frequently
'checkout.new-flow.v1'
'checkout.new-flow.v2'Avoid Environment-Specific Names
// ❌ Don't include environment in flag names
'beta-feature-dev'
'beta-feature-prod'
// ✅ Use environment-agnostic names
'beta-feature'Performance
Batch evaluation: Evaluate multiple flags in one request when possible.
const flags = await client.getFeatures({
features: ['feature-a', 'feature-b', 'feature-c'],
context: user,
})Security
Use Client Keys for frontend apps (safe to expose publicly).
Use Server Keys for backend services (keep secret).
Client keys can only read flags. Server keys have full access.
Common Anti-Patterns
Don’t Use Flags for Everything
// ❌ Don't use flags for everything
if (isFeatureEnabled('show-button')) {
return <Button />
}
// ✅ Use flags for meaningful features
if (isFeatureEnabled('new-checkout-flow')) {
return <NewCheckout />
} else {
return <OldCheckout />
}Don’t Nest Flags Deeply
// ❌ Don't nest flags deeply
if (isFeatureEnabled('feature-a')) {
if (isFeatureEnabled('feature-b')) {
if (isFeatureEnabled('feature-c')) {
// Complex nested logic
}
}
}
// ✅ Use a single flag for complex features
if (isFeatureEnabled('advanced-feature-set')) {
// Handle all advanced features together
}Clean up old flags
As part of the flag lifecycle, archive or delete flags once features are fully rolled out and stable.