界面已本地化;技能介绍与说明文档按所选语言由 AI 自动翻译,代码、命令、路径和专业术语保留原文,以原作者文档为准。
探索技能
部署与运维 · SKILL.md

feature-flags

feature-flags

【部署与运维】Feature flag management. LaunchDarkly, Unleash, Flagsmith, and custom implementations. Gradual rollouts, A/B testing, kill switches, and flag lifecycle management. USE WHEN: user mentions "feature flag", "feature toggle", "LaunchDarkly", "Unleash", "Flagsmith", "gradual rollout", "A/B test", "canary release", "kill switch" DO NOT USE FOR: CI/CD dep…

独立 GitHub 快照 · 自动分类 · 以原作者文档为准

技能说明

GitHub

name: feature-flags description: | Feature flag management. LaunchDarkly, Unleash, Flagsmith, and custom implementations. Gradual rollouts, A/B testing, kill switches, and flag lifecycle management.

USE WHEN: user mentions "feature flag", "feature toggle", "LaunchDarkly", "Unleash", "Flagsmith", "gradual rollout", "A/B test", "canary release", "kill switch"

DO NOT USE FOR: CI/CD deployment strategies - use github-actions; environment config - use environment variable patterns allowed-tools: Read, Grep, Glob, Write, Edit

Feature Flags

LaunchDarkly

import * as LaunchDarkly from '@launchdarkly/node-server-sdk';

const client = LaunchDarkly.init(process.env.LD_SDK_KEY!);
await client.waitForInitialization();

// Evaluate flag
const showNewUI = await client.variation('new-dashboard-ui', {
  key: user.id,
  email: user.email,
  custom: { plan: user.plan },
}, false); // default value

if (showNewUI) {
  renderNewDashboard();
} else {
  renderLegacyDashboard();
}

React SDK

import { useFlags, withLDProvider } from 'launchdarkly-react-client-sdk';

function Dashboard() {
  const { newDashboardUi, maxUploadSize } = useFlags();

  return newDashboardUi ? <NewDashboard maxUpload={maxUploadSize} /> : <LegacyDashboard />;
}

// Wrap app
export default withLDProvider({
  clientSideID: process.env.NEXT_PUBLIC_LD_CLIENT_ID!,
  context: { kind: 'user', key: user.id, email: user.email },
})(App);

Unleash (self-hosted)

import { initialize } from 'unleash-client';

const unleash = initialize({
  url: 'https://unleash.example.com/api',
  appName: 'my-app',
  customHeaders: { Authorization: process.env.UNLEASH_API_KEY! },
});

if (unleash.isEnabled('new-checkout', { userId: user.id })) {
  // New checkout flow
}

Custom Implementation (simple)

interface FeatureFlags {
  [key: string]: {
    enabled: boolean;
    rolloutPercentage?: number;
    allowedUsers?: string[];
  };
}

class FlagService {
  constructor(private flags: FeatureFlags) {}

  isEnabled(flag: string, userId?: string): boolean {
    const config = this.flags[flag];
    if (!config?.enabled) return false;
    if (config.allowedUsers?.includes(userId!)) return true;
    if (config.rolloutPercentage != null && userId) {
      const hash = simpleHash(userId + flag) % 100;
      return hash < config.rolloutPercentage;
    }
    return config.enabled;
  }
}

Flag Types

TypePurposeExample
BooleanOn/off togglenew-ui-enabled
Percentage rolloutGradual release10% → 50% → 100%
User targetingSpecific usersBeta testers, internal
MultivariateA/B/C testingcheckout-variant: "A"
Kill switchEmergency disablepayments-enabled

Anti-Patterns

Anti-PatternFix
Flags that live foreverSet expiration, clean up after full rollout
Flag checks deep in codeCheck at entry points, pass result down
No default valuesAlways provide sensible defaults
Testing only flagged-on pathTest both paths in CI
Flags in tight loopsCache flag evaluation result

Production Checklist

  • Default values for all flags (graceful degradation)
  • Flag naming convention (feature-name-action)
  • Cleanup process for fully-rolled-out flags
  • Monitoring: flag evaluation metrics
  • Testing both flag states in CI
  • Audit log of flag changes
我的收藏