Best Feature Flag Libraries for JavaScript in 2026
TL;DR
OpenFeature + a provider for standards-based flagging; LaunchDarkly for enterprise; Unleash for self-hosted control. OpenFeature (~200K weekly downloads) is the CNCF standard that decouples your code from any vendor. LaunchDarkly (~400K downloads) is the SaaS leader with best-in-class targeting. Unleash (~150K downloads) is the leading open-source option — self-hosted, no vendor lock-in. For new projects, code against OpenFeature so you can swap providers freely.
Key Takeaways
- LaunchDarkly: ~400K weekly downloads — SaaS leader, 99.99% uptime SLA, streaming updates
- OpenFeature: ~200K downloads — CNCF standard, vendor-neutral API, provider plugins
- Unleash: ~150K downloads — open-source, self-hosted, full feature management
- Flagsmith: ~80K downloads — open-source + SaaS, simpler than Unleash
- OpenFeature — code once, swap providers; LaunchDarkly, Unleash, Flagsmith all have OpenFeature providers
OpenFeature (The Standard)
// OpenFeature — vendor-neutral feature flag standard
import { OpenFeature } from '@openfeature/server-sdk';
// Register a provider (swap this to change vendors)
import { LaunchDarklyProvider } from '@openfeature/launchdarkly-provider';
// Or: import { UnleashProvider } from '@openfeature/unleash-provider';
// Or: import { FlagsmithProvider } from '@openfeature/flagsmith-provider';
// Or: import { InMemoryProvider } from '@openfeature/server-sdk'; // for tests
await OpenFeature.setProviderAndWait(
new LaunchDarklyProvider(process.env.LD_SDK_KEY!)
);
const client = OpenFeature.getClient();
// Boolean flag
const newCheckoutEnabled = await client.getBooleanValue(
'new-checkout-flow',
false, // default value if flag missing
);
// String flag (variants)
const checkoutVariant = await client.getStringValue(
'checkout-variant',
'control',
);
// Number flag
const maxRetries = await client.getNumberValue('max-retries', 3);
// Object flag (JSON)
const config = await client.getObjectValue('feature-config', {});
// OpenFeature — evaluation context (targeting)
import { OpenFeature, EvaluationContext } from '@openfeature/server-sdk';
const client = OpenFeature.getClient();
// Per-request context for targeting rules
const context: EvaluationContext = {
targetingKey: user.id, // Used for % rollouts
attributes: {
email: user.email,
plan: user.plan, // 'free' | 'pro' | 'enterprise'
country: user.country,
betaTester: user.betaTester,
},
};
// Flag evaluated with targeting context
const enabled = await client.getBooleanValue(
'pro-dashboard',
false,
context
);
// Result: true for pro/enterprise users, false for free
// OpenFeature — React with hooks
import { OpenFeatureProvider, useBooleanFlagValue } from '@openfeature/react-sdk';
import { OpenFeature } from '@openfeature/web-sdk';
import { LaunchDarklyClientProvider } from '@openfeature/launchdarkly-client-provider';
// Setup (client-side SDK)
await OpenFeature.setProviderAndWait(
new LaunchDarklyClientProvider(
process.env.NEXT_PUBLIC_LD_CLIENT_ID!,
{ user: { key: userId } }
)
);
// Provider wraps your app
function App() {
return (
<OpenFeatureProvider>
<Dashboard />
</OpenFeatureProvider>
);
}
// Hooks in components
function Dashboard() {
const newLayout = useBooleanFlagValue('new-dashboard-layout', false);
const variant = useStringFlagValue('dashboard-variant', 'v1');
return newLayout ? <NewDashboard variant={variant} /> : <OldDashboard />;
}
// OpenFeature — in-memory provider for tests (no external deps)
import { InMemoryProvider, OpenFeature } from '@openfeature/server-sdk';
const flagConfig = {
'new-checkout-flow': {
defaultVariant: 'on',
variants: { on: true, off: false },
},
'checkout-variant': {
defaultVariant: 'test-variant',
variants: { control: 'control', 'test-variant': 'B' },
},
};
OpenFeature.setProvider(new InMemoryProvider(flagConfig));
// Now tests run without network calls or SDK keys
LaunchDarkly (Enterprise SaaS)
// LaunchDarkly — server-side SDK
import * as ld from '@launchdarkly/node-server-sdk';
const client = ld.init(process.env.LD_SDK_KEY!, {
// Optional: polling fallback if streaming fails
stream: true,
// Optional: private attributes (not sent to LD analytics)
allAttributesPrivate: false,
privateAttributes: ['email'],
});
await client.waitForInitialization({ timeout: 5 });
// Evaluate with user context
const context: ld.LDContext = {
kind: 'user',
key: user.id,
name: user.name,
email: user.email,
custom: {
plan: user.plan,
country: user.country,
},
};
// Boolean flag
const enabled = await client.variation('dark-mode', context, false);
// String flag
const theme = await client.variation('ui-theme', context, 'default');
// Flag with detailed reason (for debugging)
const detail = await client.variationDetail('new-feature', context, false);
console.log(detail.reason); // { kind: 'RULE_MATCH', ruleIndex: 0 }
// LaunchDarkly — multi-context (user + organization)
const context: ld.LDContext = {
kind: 'multi',
user: {
kind: 'user',
key: user.id,
email: user.email,
},
organization: {
kind: 'organization',
key: org.id,
name: org.name,
plan: org.plan, // Target by org plan
},
};
// Flag can now target by user OR org attributes
const enabled = await client.variation('org-feature', context, false);
Best for: Enterprise teams needing 99.99% SLA, advanced targeting, A/B testing integration, audit logs.
Unleash (Self-Hosted Open Source)
// Unleash — self-hosted Node.js SDK
import { initialize, isEnabled } from 'unleash-client';
initialize({
url: 'https://unleash.yourcompany.com/api',
appName: 'your-app',
customHeaders: { Authorization: process.env.UNLEASH_API_TOKEN! },
});
// Simple boolean check
if (isEnabled('new-checkout', { userId: user.id })) {
// Use new checkout
}
// Unleash — full client with context
import Unleash from 'unleash-client';
const unleash = new Unleash({
url: 'https://unleash.yourcompany.com/api',
appName: 'pkgpulse',
customHeaders: { Authorization: process.env.UNLEASH_API_TOKEN! },
// Metrics reported to Unleash dashboard
metricsInterval: 60_000,
// Cache flags locally for 15s
refreshInterval: 15_000,
});
await unleash.start();
const context = {
userId: user.id,
sessionId: req.sessionId,
remoteAddress: req.ip,
properties: {
plan: user.plan,
country: user.country,
},
};
// Strategy: gradual rollout to 20% of users
const enabled = unleash.isEnabled('beta-dashboard', context);
// Variant (A/B)
const variant = unleash.getVariant('checkout-variant', context);
// variant.name = 'control' | 'A' | 'B'
// variant.payload.value = custom JSON
// Cleanup
process.on('SIGTERM', () => unleash.destroy());
// Unleash — Next.js integration
// lib/unleash.ts (server-side only)
import { createUnleash } from 'unleash-client';
let unleashInstance: Unleash;
export function getUnleash() {
if (!unleashInstance) {
unleashInstance = createUnleash({
url: process.env.UNLEASH_URL!,
appName: 'pkgpulse',
customHeaders: { Authorization: process.env.UNLEASH_API_TOKEN! },
});
}
return unleashInstance;
}
// In API route or server component
export async function GET(req: Request) {
const unleash = getUnleash();
const enabled = unleash.isEnabled('new-api', {
userId: getUserId(req),
});
return Response.json({ enabled });
}
Best for: Teams that need full control over flag data, no vendor lock-in, or have compliance requirements preventing SaaS.
Flagsmith (Simpler Self-Hosted)
// Flagsmith — simpler API, cloud + self-hosted
import Flagsmith from 'flagsmith-nodejs';
const flagsmith = new Flagsmith({
environmentKey: process.env.FLAGSMITH_ENV_KEY!,
// self-hosted: apiUrl: 'https://flagsmith.yourcompany.com/api/v1'
});
// Get all flags for a user
const flags = await flagsmith.getIdentityFlags(user.id, {
traits: {
plan: user.plan,
email: user.email,
},
});
// Check feature
const enabled = flags.isFeatureEnabled('dark-mode');
// Get remote config value
const theme = flags.getFeatureValue('theme-config');
// Returns the value set in the Flagsmith UI (string, number, JSON)
Comparison Table
| Tool | Type | Pricing | Targeting | SDK Quality | Self-Hosted |
|---|---|---|---|---|---|
| OpenFeature | Standard (no backend) | Free | Via provider | ✅ Excellent | N/A |
| LaunchDarkly | SaaS | $10+/seat | ✅ Advanced | ✅ Excellent | ❌ |
| Unleash | OSS + SaaS | Free (self-hosted) | ✅ Good | ✅ Good | ✅ |
| Flagsmith | OSS + SaaS | Free (self-hosted) | ✅ Basic | ✅ Good | ✅ |
| GrowthBook | OSS + SaaS | Free (self-hosted) | ✅ A/B focused | ✅ Good | ✅ |
When to Choose
| Scenario | Pick |
|---|---|
| Any new project | OpenFeature SDK + any provider |
| Enterprise, needs SLA + advanced targeting | LaunchDarkly |
| Full data ownership, compliance | Unleash (self-hosted) |
| Simple flags, wants self-hosted option | Flagsmith |
| A/B testing + feature flags combined | GrowthBook |
| Testing in CI without external deps | OpenFeature InMemoryProvider |
| Migrating vendors without code changes | OpenFeature |
Compare feature flag package health on PkgPulse.
See the live comparison
View launchdarkly vs. unleash on PkgPulse →