Simple in-memory feature flag system with percentage rollouts and targeting
npm install @philiprehberger/feature-flagSimple in-memory feature flag system with percentage rollouts, targeting, scheduling, A/B variants, dependency chains, and per-context overrides
npm install @philiprehberger/feature-flag
import { createFlags } from '@philiprehberger/feature-flag';
const flags = createFlags({
newCheckout: true,
darkMode: { percentage: 50 },
betaFeature: { enabled: (ctx) => ctx.role === 'beta' },
});
flags.enabled('newCheckout'); // true
flags.enabled('darkMode', { userId: 'abc' }); // deterministic by userId
flags.enabled('betaFeature', { role: 'beta' }); // true
flags.enabled('betaFeature', { role: 'user' }); // false
Enable or disable flags based on date ranges. A flag with a schedule only evaluates as enabled when the current time falls within the configured window.
const flags = createFlags({
holidaySale: {
schedule: {
startDate: '2026-12-20T00:00:00Z',
endDate: '2026-12-31T23:59:59Z',
},
},
earlyAccess: {
percentage: 25,
schedule: { startDate: new Date('2026-04-01') },
},
});
flags.enabled('holidaySale'); // true only between Dec 20-31
flags.enabled('earlyAccess', { userId: 'u1' }); // true after Apr 1 for 25% of users
Return variant IDs for multivariate testing instead of just boolean values. Variants are selected deterministically based on the context, using weights to control distribution.
const flags = createFlags({
checkoutFlow: {
variants: [
{ id: 'control', weight: 50 },
{ id: 'single-page', weight: 30 },
{ id: 'wizard', weight: 20 },
],
},
});
flags.enabled('checkoutFlow'); // true (flag has variants)
flags.variant('checkoutFlow', { userId: 'user-42' }); // 'control', 'single-page', or 'wizard'
flags.variant('unknownFlag'); // null
A flag can depend on another flag. The dependent flag only evaluates as enabled when its parent flag is also enabled.
const flags = createFlags({
newDashboard: true,
dashboardCharts: { dependsOn: 'newDashboard' },
chartAnimations: { dependsOn: 'dashboardCharts' },
});
flags.enabled('dashboardCharts'); // true (newDashboard is true)
flags.enabled('chartAnimations'); // true (entire chain is true)
Force-enable or force-disable flags for specific user IDs or organization IDs, regardless of rollout percentage or other conditions.
const flags = createFlags({
experimentalApi: {
percentage: 10,
overrides: [
{ userIds: ['admin-1', 'admin-2'], enabled: true },
{ orgIds: ['org-beta'], enabled: true },
{ userIds: ['banned-user'], enabled: false },
],
},
});
flags.enabled('experimentalApi', { userId: 'admin-1' }); // always true
flags.enabled('experimentalApi', { orgId: 'org-beta' }); // always true
flags.enabled('experimentalApi', { userId: 'banned-user' }); // always false
flags.enabled('experimentalApi', { userId: 'regular-user' }); // 10% rollout
| Export | Description |
|---|---|
createFlags(definitions) | Create a flags instance |
| Method | Returns | Description |
|---|---|---|
flags.enabled(name, context?) | boolean | Check if a flag is enabled |
flags.variant(name, context?) | string | null | Get the assigned variant ID, or null |
| Type | Example | Description |
|---|---|---|
| Boolean | true / false | Static on/off |
| Percentage | { percentage: 50 } | Deterministic rollout by userId hash |
| Function | { enabled: (ctx) => ... } | Custom targeting logic |
| Schedule | { schedule: { startDate, endDate } } | Time-based activation window |
| Variants | { variants: [{ id, weight }] } | A/B multivariate assignment |
| Dependency | { dependsOn: 'otherFlag' } | Only enabled if dependency is enabled |
| Overrides | { overrides: [{ userIds, enabled }] } | Force enable/disable per user/org |
| Type | Description |
|---|---|
FlagContext | Record<string, unknown> context passed to evaluators |
FlagDefinition | Union of all flag configuration shapes |
FlagDefinitions | Record<string, FlagDefinition> |
FlagSchedule | { startDate?: Date | string; endDate?: Date | string } |
FlagVariant | { id: string; weight: number } |
FlagOverride | { userIds?: string[]; orgIds?: string[]; enabled: boolean } |
Flags<T> | Instance returned by createFlags |
npm install
npm run build
npm test
If you find this project useful: