@roostjs/feature-flags
v0.2.0
Published
Laravel Pennant-style feature flags backed by WorkOS with KV edge caching.
Readme
@roostjs/feature-flags
Laravel Pennant-style feature flags backed by WorkOS with KV edge caching.
Part of Roost — the Laravel of Cloudflare Workers.
Installation
bun add @roostjs/feature-flagsQuick Start
import { Feature } from '@roostjs/feature-flags';
// Global flag check
if (await Feature.active('new-checkout')) {
return newCheckout(request);
}
// Scoped to a user or organization
const flags = Feature.for({ userId: 'usr_42', organizationId: 'org_7' });
if (await flags.active('beta-dashboard')) {
return betaDashboard();
}
// Typed values
const limit = await Feature.value<number>('rate-limit', 100);Features
Feature.active(flag)andFeature.value(flag, default)with optional request-scoped cachingFeature.for(context)for user/org-scoped evaluation- WorkOS as the primary provider via
@workos-inc/node - KV edge cache layer (
KVCacheFlagProvider) wraps WorkOS to avoid per-request API calls (default TTL: 60s) - KV-only provider (
KVFlagProvider) for simpler setups without WorkOS FeatureFlagMiddlewareto batch-load flags at the start of a requestFeature.fake(flags)/assertChecked(flag)for tests — no live provider needed
Setup
Register the service provider in your app bootstrap:
import { FeatureFlagServiceProvider } from '@roostjs/feature-flags';
app.register(FeatureFlagServiceProvider);The provider auto-configures based on available environment bindings:
WORKOS_API_KEY+FLAGS_KVbinding → WorkOS provider with KV cacheWORKOS_API_KEYonly → WorkOS provider (no cache)FLAGS_KVonly → KV-only provider
Batch-load flags at the route level to avoid redundant evaluations:
import { FeatureFlagMiddleware } from '@roostjs/feature-flags';
router.use(new FeatureFlagMiddleware(['new-checkout', 'beta-dashboard']));API
// Primary interface (also exported as FeatureFlag)
class Feature {
static active(flag: string, request?: Request): Promise<boolean>
static value<T>(flag: string, defaultValue?: T): Promise<T | null>
static for(context: FlagContext): ScopedFeatureFlag
static set<T>(flag: string, value: T): Promise<void>
// Testing
static fake(flags: Record<string, FlagValue>): void
static restore(): void
static assertChecked(flag: string): void
// Manual configuration
static configure(store: FlagStore): void
static configureProvider(provider: FlagProvider): void
static configureProviderWithStore(provider: FlagProvider, store: FlagStore): void
}
interface FlagContext {
userId?: string;
organizationId?: string;
[key: string]: unknown;
}
type FlagValue = boolean | number | string | Record<string, unknown>Documentation
Full documentation at roost.birdcar.dev/docs/reference/feature-flags
License
MIT
