Ecosystem/18feature-flags

feature-flags

npm version

GitHub: Stackbilt-dev/feature-flags · MIT

Part of the Stackbilt ecosystem. High-performance feature flag system for Cloudflare Workers with <5ms evaluation latency. KV-backed, Hono middleware included, audit logging built in.


Install

npm install @stackbilt/feature-flags

Add KV namespaces to wrangler.toml:

[[kv_namespaces]]
binding = "FEATURE_FLAGS_KV"
id = "your-flags-kv-id"

[[kv_namespaces]]
binding = "FEATURE_FLAGS_CACHE"
id = "your-cache-kv-id"

Quick Start

import { createProductionFeatureFlags, createFeatureFlagMiddleware } from '@stackbilt/feature-flags';
import { Hono } from 'hono';

const app = new Hono();
const flagSystem = createProductionFeatureFlags(env);

app.use('*', createFeatureFlagMiddleware({ manager: flagSystem.manager }));

app.get('/api/data', async (c) => {
  const flags = c.get('featureFlags');
  const useNew = await flags.isEnabled('new_feature');
  return c.json({ data: useNew ? getNewData() : getLegacyData() });
});

Flag Types

Boolean flags

Simple on/off toggles:

await manager.createFlag({ key: 'dark_mode', type: 'boolean', enabled: true });
const isOn = await flags.isEnabled('dark_mode');

Percentage rollouts

Consistent user assignment across requests:

await manager.createFlag({
  key: 'new_dashboard',
  type: 'percentage',
  percentage: 25, // 25% of users
});

Variant flags (A/B/n testing)

await manager.createFlag({
  key: 'checkout_flow',
  type: 'variant',
  variants: [
    { key: 'control', weight: 50 },
    { key: 'streamlined', weight: 30 },
    { key: 'one_page', weight: 20 },
  ],
});

const variant = await flags.getVariant('checkout_flow');
// Returns 'control' | 'streamlined' | 'one_page' based on user hash

Canary Deployments

Staged rollouts with automatic advancement:

import { createCanaryFlags } from '@stackbilt/feature-flags';

const { gradualRollout, canaryConfig } = createCanaryFlags();
await manager.createFlag(gradualRollout);

// Start at 5%, auto-advance through stages: 5% → 10% → 25% → 50% → 100%
await manager.startCanaryDeployment('gradual_rollout_feature', canaryConfig);

// Manual advance
await manager.updateCanaryDeployment('gradual_rollout_feature', { percentage: 25 });

// Emergency rollback
await manager.stopCanaryDeployment('gradual_rollout_feature');

Tenant Overrides

Per-tenant flag values for multi-tenant deployments:

// Override for a specific tenant
await manager.setTenantOverride('tenant-123', 'new_feature', true);

// Evaluate with tenant context
const flags = manager.forTenant('tenant-123');
const isOn = await flags.isEnabled('new_feature'); // uses override

Rule Engine

Target by tenant, user, IP, custom attributes, or time windows:

await manager.createFlag({
  key: 'beta_feature',
  type: 'boolean',
  rules: [
    { attribute: 'plan', operator: 'equals', value: 'pro', result: true },
    { attribute: 'country', operator: 'in', value: ['US', 'CA'], result: true },
    { attribute: 'created_at', operator: 'after', value: '2026-01-01', result: false },
  ],
  default: false,
});

Admin API

REST endpoints for flag management (auth-gated):

Method Path Description
GET /flags List all flags
POST /flags Create a flag
PATCH /flags/:key Update a flag
DELETE /flags/:key Delete a flag
GET /flags/:key/metrics Evaluation counts + variant distribution
POST /flags/:key/canary/start Start canary deployment
POST /flags/:key/canary/stop Rollback canary

Metrics

Evaluation metrics per flag:

const metrics = await manager.getMetrics('checkout_flow');
// {
//   evaluations: 42000,
//   variants: { control: 21200, streamlined: 12600, one_page: 8200 },
//   p50LatencyMs: 2.1, p99LatencyMs: 4.8
// }

All flag changes are written to an audit log in KV with timestamps and actor identity.