Complete guide to implementing feature flags in React and Node.js applications
For React, Next.js, and browser applications
For backend services, APIs, and serverless functions
npm install @flagswift/react-clientCreate a FlagClient instance and wrap your application with the FlagProvider:
// app/providers.tsx
'use client'
import { FlagProvider, FlagClient } from '@flagswift/react-client'
const client = new FlagClient({
apiKey: process.env.NEXT_PUBLIC_FLAGSWIFT_API_KEY!,
environment: process.env.NEXT_PUBLIC_ENVIRONMENT || 'production',
userIdentifier: 'user@example.com', // Optional: for user targeting
baseUrl: 'https://flagswift.com', // Optional: defaults to flagswift.com
refreshInterval: 30000 // Optional: auto-refresh every 30s
})
export function Providers({ children }: { children: React.ReactNode }) {
return (
<FlagProvider client={client}>
{children}
</FlagProvider>
)
}Use the useFlag hook to check if a feature is enabled:
import { useFlag } from '@flagswift/react-client'
function MyComponent() {
const showNewFeature = useFlag('new-dashboard')
if (showNewFeature) {
return <NewDashboard />
}
return <LegacyDashboard />
}Get loading states and error handling with useFlagMeta:
import { useFlagMeta } from '@flagswift/react-client'
function Dashboard() {
const { enabled, loading, error } = useFlagMeta('analytics-dashboard')
if (loading) {
return <LoadingSpinner />
}
if (error) {
console.error('Flag error:', error)
return <StandardDashboard />
}
return enabled ? <AnalyticsDashboard /> : <StandardDashboard />
}Target multiple users or groups by passing an array of identifiers:
import { FlagProvider, FlagClient } from '@flagswift/react-client'
function App({ currentUser, teamMembers }) {
const userIdentifiers = [
currentUser.email,
...teamMembers.map(member => member.email)
]
const client = new FlagClient({
apiKey: process.env.NEXT_PUBLIC_FLAGSWIFT_API_KEY!,
environment: 'production',
userIdentifier: userIdentifiers
})
return (
<FlagProvider client={client}>
<Dashboard />
</FlagProvider>
)
}useFlag(flagName: string): booleanReturns true if the flag is enabled, false otherwise
useFlagMeta(flagName: string)Returns { enabled: boolean, loading: boolean, error: string | null }
useFlagContext()Access all flags and context information
npm install @flagswift/node-serverInitialize the FlagSwiftServer client once and reuse it throughout your application:
import { FlagSwiftServer } from '@flagswift/node-server'
const flagClient = new FlagSwiftServer({
apiKey: 'YourFlagserverApiKey',
environment: 'production',
baseUrl: 'https://example.com', // Optional: custom API URL
})
flagSwiftClient
.initialize()
.then(() => {
console.log('✅ FlagSwift Server SDK initialized')
})
.catch((err) => {
console.error('❌ Failed to initialize SDK:', err)
})
export default flagClientimport flagClient from './flagClient'
async function handleRequest(req, res) {
const targetedUser = {
identifier: 'req.query.targetedUser' // Single identifier
}
// Or with multiple identifiers:
const targetedUser = {
identifier: [req.query.targetedUser, req.user.id],
attributes: { plan: 'premium' }
}
const newFeatureEnabled = flagClient.isEnabled('new-algorithm', targetedUser)
if (newFeatureEnabled) {
return await processWithNewAlgorithm(req.data)
}
return await processWithLegacyAlgorithm(req.data)
}Flagswift setup with enhanced configuration pattern
import { FlagSwiftServer } from "@flagswift/node-server";
const flagSwiftClient = new FlagSwiftServer({
apiKey: "YourserverApiKey",
environment: "staging",
baseUrl: "https://custom-flagswift.com", // Optional: custom API URL
refreshInterval: 10000,
});
let isInitialized = false;
export async function initializeFlagSwift(): Promise<FlagSwiftServer> {
if (isInitialized) {
console.log("✅ FlagSwift already initialized");
return flagSwiftClient;
}
try {
await flagSwiftClient.initialize();
isInitialized = true;
console.log("✅ FlagSwift Client initialized successfully");
return flagSwiftClient;
} catch (error) {
console.error("❌ Failed to initialize FlagSwift:", error);
throw error;
}
}
export function getFlagSwiftClient(): FlagSwiftServer {
if (!isInitialized) {
console.warn("⚠️ FlagSwift client accessed before initialization");
}
return flagSwiftClient;
}
export function isFlagSwiftReady(): boolean {
return isInitialized;
}
export default flagSwiftClient;Emergency disable flags instantly with optional database sync:
// DISABLE SPECIFIC FLAGS: Required parameter
await flagClient.activateKillSwitch({
flags: ['new-checkout', 'beta-feature']
})
// SINGLE FLAG: Can pass as string
await flagClient.activateKillSwitch({
flags: 'new-checkout'
})
// SPECIFIC ENVIRONMENT: Only disable production (note: plural 'environments')
await flagClient.activateKillSwitch({
flags: 'new-checkout',
environments: 'production'
})
// MULTIPLE ENVIRONMENTS: Disable across environments
await flagClient.activateKillSwitch({
flags: ['new-checkout'],
environments: ['production', 'staging']
})
// RESTORE: Reactivate and restore previous state
await flagClient.deactivateKillSwitch({
flags: ['new-checkout', 'beta-feature'],
environments: 'production'
})
// CHECK STATUS
if (flagClient.isKillSwitchEnabled()) {
console.log('⚠️ Kill switch is active')
}Check multiple flags efficiently:
const targetUsers = {
identifier: ['user@example.com', 'user123']
}
const features = flagClient.evaluateFlags([
'new-dashboard',
'premium-features',
'beta-ui'
], targetUsers)
console.log(features)
// { 'new-dashboard': true, 'premium-features': false, 'beta-ui': true }Check if a user is specifically targeted:
const targetUser = {
identifier: ['user@example.com', 'user123']
}
// Check if user is in the target list
const isTargeted = flagClient.isUserTargeted('beta-program', targetUser)For one-off flag checks without initializing a full client:
import { checkFlag } from '@flagswift/node-server'
async function processPayment() {
const useNewProcessor = await checkFlag('new-payment-processor', {
apiKey: process.env.FLAGSWIFT_SERVER_KEY!,
environment: 'production',
user: { identifier: 'service-account@app.com' }, // Optional
killSwitchFallback: false
})
return useNewProcessor ? newPaymentFlow() : legacyPaymentFlow()
// Example: Manual identifiers
const manualUser = {
identifier: ["admin@company.com", "support@company.com"]
}
// Check flags for these emails
const hasAccess = flagClient.isEnabled('admin-panel', manualUser)
}isEnabled(flagName, user?): booleanCheck if flag is enabled for a user
evaluateFlags(flagNames[], user?)Evaluate multiple flags at once
activateKillSwitch()Emergency disable all flags
isUserTargeted(flagName, user?): booleanCheck if user is in target list
getStatus()Get SDK initialization and cache status
New flags enabled by default. Perfect for local testing.
environment: 'development'Test with production-like data before launch.
environment: 'staging'Safe by default. Enable when ready to launch.
environment: 'production'NEXT_PUBLIC_FLAGSWIFT_API_KEY=fs_client_...
NEXT_PUBLIC_ENVIRONMENT=productionFLAGSWIFT_SERVER_KEY=fs_server_...
FLAGSWIFT_ENVIRONMENT=productionCreate FlagClient/FlagSwiftServer once and reuse throughout your app
Name flags clearly: 'new-checkout-flow' not 'feature-123'
Use useFlagMeta for loading states to prevent hydration issues
Define fallback values for critical features
Configure killSwitchFallbacks for payment, auth, etc.
Use cacheTimeout to reduce API calls and improve performance
Use email, username, or ID consistently across environments
Remove flags after full rollout to keep codebase clean
userIdentifier: Can be email, username, user ID, or any consistent identifier
Target Lists: Add specific users to your flag's target list in the FlagSwift dashboard
Targeting Behavior: Only users in the target list will see the feature when targeting is enabled
Multi-user support: Pass an array of identifiers to check multiple users at once
FlagSwift uses targeted user lists set in your dashboard. When you add users to a flag's target list, those specific users will see the feature.
// Check if user is in the target list
const targetUser = {
identifier: req.query.targetUser // Single identifier
}
// This checks against the target list you set in FlagSwift dashboard
const isTargeted = flagClient.isUserTargeted('beta-program', targetUser)
if (isTargeted) {
console.log('User is in the beta program target list')
}