Feature Flag Manager
Implement comprehensive feature flag management for controlled feature rollouts and A/B testing in worldbuilding applications.
Overview
To add feature flag capabilities:
-
Choose between LaunchDarkly (cloud service) or JSON-based (local) implementation
-
Set up feature flag provider with configuration
-
Create feature flag components and hooks
-
Gate UI components and Server Actions behind flags
-
Implement user targeting and progressive rollouts
Implementation Options
LaunchDarkly Integration
To integrate LaunchDarkly:
-
Install LaunchDarkly SDK: npm install launchdarkly-react-client-sdk
-
Configure provider in app root with client-side ID
-
Create hooks for flag evaluation
-
Wrap components with feature flag checks
-
Configure flags in LaunchDarkly dashboard
Use scripts/setup_launchdarkly.py to scaffold LaunchDarkly configuration.
JSON-Based Feature Flags
To implement local JSON-based flags:
-
Create config/feature-flags.json with flag definitions
-
Build feature flag provider context
-
Create hooks to read flags from context
-
Implement environment-specific overrides
-
Support runtime flag updates
Use scripts/setup_json_flags.py to generate JSON flag structure.
Consult references/feature-flag-patterns.md for implementation patterns and best practices.
Feature Flag Provider Setup
LaunchDarkly Provider
To set up LaunchDarkly in Next.js:
// app/providers.tsx import { LDProvider } from 'launchdarkly-react-client-sdk';
export function Providers({ children }: { children: React.ReactNode }) { return ( <LDProvider clientSideID={process.env.NEXT_PUBLIC_LD_CLIENT_ID} user={{ key: 'user-id', email: 'user@example.com', }} > {children} </LDProvider> ); }
JSON Provider
To create custom JSON provider:
// lib/feature-flags/provider.tsx import { createContext, useContext } from 'react'; import flags from '@/config/feature-flags.json';
const FeatureFlagContext = createContext(flags);
export function FeatureFlagProvider({ children }: { children: React.ReactNode }) { return ( <FeatureFlagContext.Provider value={flags}> {children} </FeatureFlagContext.Provider> ); }
export function useFeatureFlags() { return useContext(FeatureFlagContext); }
Reference assets/feature-flag-provider.tsx for complete provider implementation.
Using Feature Flags
Component Gating
To gate UI components behind flags:
import { useFeatureFlag } from '@/lib/feature-flags';
export function NewFeatureComponent() { const isEnabled = useFeatureFlag('new-timeline-view');
if (!isEnabled) { return null; }
return <div>New Timeline View</div>; }
Conditional Rendering
To show different variants based on flags:
export function EntityList() { const useNewLayout = useFeatureFlag('entity-list-redesign');
return useNewLayout ? <NewEntityList /> : <LegacyEntityList />; }
Server Action Gating
To gate Server Actions:
// app/actions/entity-actions.ts 'use server';
import { getFeatureFlag } from '@/lib/feature-flags/server';
export async function createEntity(data: EntityData) { const allowBulkCreate = await getFeatureFlag('bulk-entity-creation');
if (allowBulkCreate && data.items?.length > 1) { return bulkCreateEntities(data.items); }
return createSingleEntity(data); }
Reference assets/server-actions-with-flags.ts for server-side flag patterns.
Flag Configuration
Flag Structure
Define flags with metadata:
{ "flags": { "new-timeline-view": { "enabled": true, "description": "Enable new timeline visualization", "rolloutPercentage": 100, "allowedUsers": [], "environments": { "development": true, "staging": true, "production": false } } } }
Flag Types
Support different flag types:
-
Boolean: Simple on/off toggle
-
Percentage: Gradual rollout (0-100%)
-
User Targeting: Specific users or groups
-
Multivariate: Multiple variations (A/B/C testing)
Consult references/flag-types.md for detailed flag type specifications.
Progressive Rollout
To implement gradual feature rollouts:
-
Initial Release: Enable for 5% of users
-
Monitor Metrics: Track performance and errors
-
Increase Rollout: Gradually increase to 25%, 50%, 100%
-
Full Release: Enable for all users
-
Remove Flag: Clean up flag code after stable release
Use scripts/rollout_manager.py to automate rollout percentage updates.
User Targeting
To target specific user segments:
By User ID
const flags = evaluateFlags(userId, flagConfig);
By User Properties
const flags = evaluateFlags({ userId: 'user-123', email: 'user@example.com', role: 'admin', tier: 'premium', });
By Custom Rules
const flags = evaluateFlags(user, { rules: [ { property: 'role', operator: 'equals', value: 'admin' }, { property: 'tier', operator: 'in', values: ['premium', 'enterprise'] }, ], });
Environment-Specific Flags
To configure flags per environment:
{ "flags": { "debug-mode": { "development": true, "staging": true, "production": false }, "experimental-features": { "development": true, "staging": false, "production": false } } }
Load environment-specific configuration at build time or runtime.
A/B Testing
To implement A/B tests:
export function EntityDetailPage() { const variant = useFeatureFlagVariant('entity-detail-layout', { control: 'grid', variantA: 'list', variantB: 'cards', });
return variant === 'list' ? ( <EntityListView /> ) : variant === 'cards' ? ( <EntityCardView /> ) : ( <EntityGridView /> ); }
Track variant exposure for analytics:
useEffect(() => { trackExposure('entity-detail-layout', variant); }, [variant]);
Flag Lifecycle Management
Creating New Flags
To add a new feature flag:
-
Define flag in configuration with metadata
-
Set initial state (usually disabled)
-
Implement flag checks in code
-
Deploy with flag disabled
-
Enable flag via dashboard or config update
Removing Old Flags
To clean up completed feature flags:
-
Ensure flag is at 100% rollout
-
Verify no incidents for 2+ weeks
-
Remove flag checks from code
-
Make flagged code permanent
-
Remove flag from configuration
-
Deploy cleanup changes
Use scripts/find_flag_usage.py to locate all usages of a flag before removal.
Testing with Feature Flags
Local Development
To override flags in development:
// .env.local NEXT_PUBLIC_FEATURE_FLAGS_OVERRIDE='{"new-timeline-view":true}'
Testing Specific Variants
To test flag variations:
// test/setup.ts import { mockFeatureFlags } from '@/lib/feature-flags/testing';
beforeEach(() => { mockFeatureFlags({ 'new-timeline-view': true, 'bulk-entity-creation': false, }); });
Reference assets/testing-utils.ts for testing utilities.
Monitoring and Analytics
To track feature flag impact:
-
Exposure Tracking: Log when flags are evaluated
-
Performance Metrics: Monitor performance per variant
-
Error Rates: Track errors by flag state
-
User Engagement: Measure feature usage
-
Conversion Metrics: Track business metrics per variant
Integrate with analytics platform:
import { analytics } from '@/lib/analytics';
export function useFeatureFlagWithTracking(flagName: string) { const isEnabled = useFeatureFlag(flagName);
useEffect(() => { analytics.track('feature_flag_exposure', { flag: flagName, enabled: isEnabled, }); }, [flagName, isEnabled]);
return isEnabled; }
LaunchDarkly-Specific Features
To leverage LaunchDarkly capabilities:
-
Targeting Rules: Create complex targeting rules in dashboard
-
Flag Triggers: Automate flag changes based on metrics
-
Scheduled Rollouts: Plan feature releases in advance
-
Flag Dependencies: Define flag prerequisites
-
Audit Logs: Track all flag changes
-
Team Workflows: Require approvals for production changes
Consult LaunchDarkly documentation for advanced features.
Best Practices
-
Short-Lived Flags: Remove flags after rollout completes
-
Clear Naming: Use descriptive, consistent flag names
-
Documentation: Document flag purpose and timeline
-
Default Values: Provide safe defaults for missing flags
-
Testing: Test both enabled and disabled states
-
Monitoring: Track flag performance and errors
-
Cleanup: Regularly audit and remove unused flags
Troubleshooting
Common issues:
-
Flag Not Updating: Check cache settings and invalidation
-
Inconsistent State: Verify flag evaluation consistency
-
Performance Impact: Minimize flag evaluation overhead
-
Testing Challenges: Use proper mocking in tests
-
Configuration Conflicts: Ensure environment-specific overrides work correctly