PromptShop

Feature Flags

This skill guides developers in implementing and managing React feature flags.

Install

npx promptshop add feature-flags

Details

What This Skill Does

This skill guides developers in implementing and managing React feature flags. It provides instructions on how to add new flags, gate tests, check flag states across different channels, and debug channel-specific failures. This allows for controlled rollout of new features and A/B testing.

When to Use

  • Rolling out new features gradually.
  • Performing A/B testing.
  • Enabling features for specific user groups.
  • Disabling buggy features quickly.
  • Testing experimental features in production.
  • Managing different feature sets across channels.

Key Features

  • Manages feature flags in React applications.
  • Supports multiple flag files for different channels.
  • Offers @gate pragma for test-level gating.
  • Includes gate() inline for assertion-level gating.
  • Provides /flags command to view flag states.
  • Handles __VARIANT__ flags for gatekeeper simulations.

Manual Installation

React Feature Flags

Flag Files

FilePurpose
packages/shared/ReactFeatureFlags.jsDefault flags (canary), EXPERIMENTAL overrides
packages/shared/forks/ReactFeatureFlags.www.jswww channel, VARIANT overrides
packages/shared/forks/ReactFeatureFlags.native-fb.jsReact Native, VARIANT overrides
packages/shared/forks/ReactFeatureFlags.test-renderer.jsTest renderer

Gating Tests

@gate pragma (test-level)

Use when the feature is completely unavailable without the flag:

// @gate enableViewTransition it('supports view transitions', () => { // This test only runs when enableViewTransition is true // and is SKIPPED (not failed) when false });

gate() inline (assertion-level)

Use when the feature exists but behavior differs based on flag:

it('renders component', async () => { await act(() => root.render(<App />));

if (gate(flags => flags.enableNewBehavior)) { expect(container.textContent).toBe('new output'); } else { expect(container.textContent).toBe('legacy output'); } });

Adding a New Flag

Add to ReactFeatureFlags.js with default value Add to each fork file (.www.js, .native-fb.js, etc.) If it should vary in www/RN, set to VARIANT in the fork file Gate tests with @gate flagName or inline gate()

Checking Flag States

Use /flags to view states across channels. See the flags skill for full command options.

VARIANT Flags (GKs)

Flags set to VARIANT simulate gatekeepers - tested twice (true and false):

/test www <pattern> # VARIANT = true /test www variant false <pattern> # VARIANT = false

Debugging Channel-Specific Failures

Run /flags --diff to compare values Check @gate conditions - test may be gated to specific channels Run /test to isolate the failure Verify flag exists in all fork files if newly added

Common Mistakes

Forgetting both variants - Always test www AND www variant false for VARIANT flags Using @gate for behavior differences - Use inline gate() if both paths should run Missing fork files - New flags must be added to ALL fork files, not just the main one Wrong gate syntax - It's gate(flags => flags.name), not gate('name')

React Feature Flags

Flag Files

FilePurpose
packages/shared/ReactFeatureFlags.jsDefault flags (canary), EXPERIMENTAL overrides
packages/shared/forks/ReactFeatureFlags.www.jswww channel, VARIANT overrides
packages/shared/forks/ReactFeatureFlags.native-fb.jsReact Native, VARIANT overrides
packages/shared/forks/ReactFeatureFlags.test-renderer.jsTest renderer

Gating Tests

@gate pragma (test-level)

Use when the feature is completely unavailable without the flag:

// @gate enableViewTransition it('supports view transitions', () => { // This test only runs when enableViewTransition is true // and is SKIPPED (not failed) when false });

gate() inline (assertion-level)

Use when the feature exists but behavior differs based on flag:

it('renders component', async () => { await act(() => root.render(<App />));

if (gate(flags => flags.enableNewBehavior)) { expect(container.textContent).toBe('new output'); } else { expect(container.textContent).toBe('legacy output'); } });

Adding a New Flag

Add to ReactFeatureFlags.js with default value Add to each fork file (.www.js, .native-fb.js, etc.) If it should vary in www/RN, set to VARIANT in the fork file Gate tests with @gate flagName or inline gate()

Checking Flag States

Use /flags to view states across channels. See the flags skill for full command options.

VARIANT Flags (GKs)

Flags set to VARIANT simulate gatekeepers - tested twice (true and false):

/test www <pattern> # VARIANT = true /test www variant false <pattern> # VARIANT = false

Debugging Channel-Specific Failures

Run /flags --diff to compare values Check @gate conditions - test may be gated to specific channels Run /test to isolate the failure Verify flag exists in all fork files if newly added

Common Mistakes

Forgetting both variants - Always test www AND www variant false for VARIANT flags Using @gate for behavior differences - Use inline gate() if both paths should run Missing fork files - New flags must be added to ALL fork files, not just the main one Wrong gate syntax - It's gate(flags => flags.name), not gate('name')