Best Practices
Guidelines for using feature flags effectively and avoiding common pitfalls.
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
Remove flags after features are fully rolled out. Archive or delete flags that are no longer needed to keep your project organized.
Last updated on