Configuration Guide
Set up the FlagsProvider and configure your feature flags for maximum flexibility
Table of Contents
Basic Setup
Get your application ready for feature flags
The first step is to wrap your application with the FlagsProvider component. This provides the feature flags context to all child components.
import React from 'react';
import { FlagsProvider } from '@pursuit-amsterdam/feature-flags';
import { AppComponent } from './components/AppComponent';
// Define your feature flags
const featureFlags = {
newHeader: true,
betaFeatures: false,
darkMode: true,
} as const;
function App() {
return (
<FlagsProvider config={featureFlags}>
<AppComponent />
</FlagsProvider>
);
}
export default App;That's it!
FlagsProvider Configuration
Understanding all available options
The FlagsProvider accepts several configuration options to customize its behavior:
Configuration Options
config (required)
The initial feature flags configuration object
children (required)
React children components to wrap
Automatic Features
import { FlagsProvider } from '@pursuit-amsterdam/feature-flags';
const flags = {
// Your flags here
} as const;
function App() {
return (
<FlagsProvider config={flags}>
}}
syncAcrossTabs={true}
>
<YourApp />
</FlagsProvider>
);
}Defining Feature Flags
Best practices for structuring your flags
Feature flags should be defined as a configuration object with meaningful names and appropriate default values.
// flags.ts
export const featureFlags = {
// UI/UX Features
useNewHeader: true,
enableDarkMode: false,
showNotifications: true,
// Experimental Features
betaSearch: false,
advancedFilters: false,
// Access Control
adminPanel: false,
premiumFeatures: false,
// Development/Debug
debugMode: false,
verboseLogging: false,
// Business Logic
newPaymentFlow: false,
enhancedAnalytics: true,
} as const;
// Export the type for TypeScript support
export type AppFlags = typeof featureFlags;Naming Conventions
useNewHeader - Clear actionenableDarkMode - Clear intentionshowBetaFeatures - Clear visibilityflag1 - Not descriptivetemp - Not permanent namingFlag Categories
UI/UX Flags
- • Visual design changes
- • Layout modifications
- • Theme switches
Feature Flags
- • New functionality
- • Beta features
- • Experimental features
Access Control
- • Role-based features
- • Premium content
- • Admin functionality
Operational
- • Debug modes
- • Maintenance modes
- • Performance toggles
Environment Variables
Integrating with your deployment pipeline
The library provides a boolFromEnv utility function to easily integrate feature flags with environment variables.
import { boolFromEnv } from '@pursuit-amsterdam/feature-flags/server';
export const featureFlags = {
// Read from environment variables with fallback defaults
useNewHeader: boolFromEnv(process.env.REACT_APP_NEW_HEADER, true),
betaFeatures: boolFromEnv(process.env.REACT_APP_BETA_FEATURES, false),
debugMode: boolFromEnv(process.env.REACT_APP_DEBUG_MODE, false),
// Can also use direct boolean values
alwaysEnabled: true,
neverEnabled: false,
} as const;Environment Files
Create different environment files for each deployment stage:
.env.development
REACT_APP_NEW_HEADER=true
REACT_APP_BETA_FEATURES=true
REACT_APP_DEBUG_MODE=true.env.staging
REACT_APP_NEW_HEADER=true
REACT_APP_BETA_FEATURES=false
REACT_APP_DEBUG_MODE=false.env.production
REACT_APP_NEW_HEADER=false
REACT_APP_BETA_FEATURES=false
REACT_APP_DEBUG_MODE=falseThis Demo Configuration
packages/demo-app/src/config/flags.ts.Current Environment Values
See how your current flags are configured
Demo App Pattern
Real-world configuration pattern used in this demo
This demo application demonstrates a production-ready pattern for organizing feature flags using environment variables with fallback defaults. Let's examine the actual configuration used in packages/demo-app/src/config/flags.ts:
import { boolFromEnv } from '@pursuit-amsterdam/feature-flags/server';
// Demo feature flags configuration
export const demoFlags = {
useNewHeader: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_USE_NEW_HEADER,
true
),
showBetaFeatures: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_SHOW_BETA_FEATURES,
false
),
enableDarkMode: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_ENABLE_DARK_MODE,
false
),
useAdvancedSearch: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_USE_ADVANCED_SEARCH,
true
),
showNotifications: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_SHOW_NOTIFICATIONS,
true
),
enableAnalytics: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_ENABLE_ANALYTICS,
false
),
premiumFeatures: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_PREMIUM_FEATURES,
false
),
maintenanceMode: boolFromEnv(
process.env.NEXT_PUBLIC_FLAG_MAINTENANCE_MODE,
false
),
debugMode: boolFromEnv(process.env.NEXT_PUBLIC_FLAG_DEBUG_MODE, false),
superAdmin: boolFromEnv(process.env.NEXT_PUBLIC_FLAG_SUPER_ADMIN, false),
} as const;
export type DemoFlags = typeof demoFlags;Pattern Analysis
1. Consistent Naming Convention
All environment variables follow the NEXT_PUBLIC_FLAG_* pattern:
- •
NEXT_PUBLIC_- Next.js client-side access - •
FLAG_- Clear identification as feature flag - •
DESCRIPTIVE_NAME- Self-documenting purpose
2. Strategic Default Values
Each flag has a carefully chosen default that makes sense for development:
Enabled by Default (true)
useNewHeader - Safe UI updatesuseAdvancedSearch - Enhanced UXshowNotifications - User engagementDisabled by Default (false)
showBetaFeatures - ExperimentalenableAnalytics - Privacy-firstpremiumFeatures - Access controlmaintenanceMode - Emergency only3. TypeScript Integration
The pattern includes complete TypeScript support:
- •
as constensures immutability - •
typeof demoFlagsderives accurate types - • Exported type enables IDE autocomplete and validation
Benefits of This Pattern
Environment Flexibility
Override any flag via environment variables without code changes
Development Ready
Sensible defaults mean immediate productivity
Type Safety
Full TypeScript support with autocomplete
Self-Documenting
Clear naming makes purpose obvious
Deployment Control
Different flags per environment (dev/staging/prod)
Categorized
Logical grouping by functionality
Adopting This Pattern
Storage & Encryption
How flags are persisted and secured
The library automatically handles flag persistence using encrypted localStorage. This ensures that user preferences are saved and synchronized across browser sessions.
Storage Features
Automatic Encryption
All flag data is encrypted before being stored in localStorage
Cross-tab Sync
Changes in one tab are instantly reflected in all other tabs
Fallback to Defaults
If localStorage is unavailable, flags fall back to their default values
import { FlagsProvider } from '@pursuit-amsterdam/feature-flags';
const customEncryption = {
secretKey: process.env.REACT_APP_ENCRYPTION_KEY,
algorithm: 'AES-GCM',
keyDerivation: 'PBKDF2'
};
function App() {
return (
<FlagsProvider
config={flags}
encryption={customEncryption}
config={featureFlags}
>
<YourApp />
</FlagsProvider>
);
}TypeScript Setup
Getting the most out of type safety
The library is built with TypeScript and provides full type safety for your feature flags. Here's how to set it up properly:
// types/flags.ts
export const appFlags = {
useNewHeader: true,
showBetaFeatures: false,
enableDarkMode: true,
premiumFeatures: false,
} as const;
// Export the type for use throughout your app
export type AppFlags = typeof appFlags;
// Optional: Create a branded type for even stronger typing
export type FlagKey = keyof AppFlags;import { useFeatureFlags } from '@pursuit-amsterdam/feature-flags';
import type { AppFlags, FlagKey } from './types/flags';
function MyComponent() {
// Full type safety with auto-completion
const { flags, toggleFlag, setFlag } = useFeatureFlags<AppFlags>();
// TypeScript will prevent typos and ensure flag exists
const handleToggle = (flagName: FlagKey) => {
toggleFlag(flagName); // ✅ Type-safe
};
// This would cause a TypeScript error:
// toggleFlag('nonExistentFlag'); // ❌ Error
return (
<div>
{flags.useNewHeader && <NewHeader />}
<button onClick={() => handleToggle('showBetaFeatures')}>
Toggle Beta Features
</button>
</div>
);
}TypeScript Benefits
Best Practices
Tips for effective feature flag management
🎯 Flag Lifecycle
1. Introduction
Start with flag disabled, enable for specific users/environments
2. Gradual Rollout
Gradually increase exposure, monitor metrics and feedback
3. Full Deployment
Enable for all users once confidence is high
4. Cleanup
Remove flag and old code path after successful rollout
💡 Organization Tips
Do's
- • Use descriptive, meaningful names
- • Group related flags together
- • Document flag purpose and timeline
- • Set appropriate default values
- • Regular flag cleanup and review
Don'ts
- • Use generic names like 'flag1', 'temp'
- • Leave obsolete flags in code
- • Create flags for every small change
- • Ignore flag performance impact
- • Forget to remove flags after rollout
🚀 Performance Considerations
Ready to implement feature flags?
Now that you understand configuration, let's explore the component APIs and see them in action.
Explore Components →