FeatureFlag enum in the warp_features crate, evaluated at runtime via is_enabled(), and organized into static arrays that determine their default state in dogfood, preview, and release builds. This approach lets you ship incomplete features safely, run A/B experiments via server-side experiments, and clean up dead code after a feature graduates to stable.
The FeatureFlag enum
All flags live in a singleFeatureFlag enum in crates/warp_features/src/lib.rs. The enum derives Sequence (from the enum_iterator crate) so the framework can iterate over all variants to initialize and manage state arrays.
AtomicBool slot in a static FLAG_STATES array. The index is determined by the variant’s position in the Sequence iteration order, so variants must never be reordered or removed until the flag is fully cleaned up.
Rollout stages
Flags graduate through a series of static arrays, each representing a broader audience:- DEBUG_FLAGS
- DOGFOOD_FLAGS
- PREVIEW_FLAGS
- RELEASE_FLAGS
Enabled only in local debug builds. Used for low-level diagnostics that
should never reach any users.
How to add a new flag
Add the variant to FeatureFlag
Open Add it near related flags for readability, but do not reorder existing
variants — their array indices are load-bearing.
crates/warp_features/src/lib.rs and add your variant to the
FeatureFlag enum. Add a doc comment explaining what the flag gates:Optionally add to a rollout array
Add the variant to Skip this step if you want the flag off everywhere by default (e.g., for
a server-controlled experiment that is toggled via
DOGFOOD_FLAGS if you want it on by default for
internal builds, or to PREVIEW_FLAGS for preview users:set_enabled).Gate code paths with is_enabled()
Use For UI components, gate the entire component’s construction:
FeatureFlag::YourFlag.is_enabled() at each gated call site:Checking flag state
is_enabled() resolves state in priority order:
- Thread-local test override (if set via
override_enabled) - User preference (set via
set_user_preference, e.g. from a UI toggle) - Global flag state (set at startup from
DOGFOOD_FLAGS,PREVIEW_FLAGS,RELEASE_FLAGS, or server experiments)
Runtime and server-controlled flags
Some flags are toggled at runtime by the server rather than at startup. The server can enable or disable flags via aServerExperiment mechanism. For example, CreatingSharedSessions is enabled for paying team plans and members of the session-sharing experiment group, even without the flag being in DOGFOOD_FLAGS.
The RuntimeFeatureFlags flag gates the runtime toggle mechanism itself — when it is on, the set of RUNTIME_FEATURE_FLAGS can be changed without restarting.
Testing with flag overrides
In unit tests, useoverride_enabled to set a flag for the duration of the test without affecting global state. The override is thread-local and automatically reverts when the returned guard is dropped:
Best practices
- Prefer runtime checks: use
FeatureFlag::YourFlag.is_enabled()over#[cfg(...)]compile-time directives so flags can be toggled without recompilation and are easier to clean up. Reserve#[cfg(...)]for code that genuinely cannot compile without the feature (platform-specific dependencies, etc.). - Keep flags high-level and product-focused: one flag per feature, not one flag per call site.
- Remove flags after launch: once a feature has stabilized in a release build, delete the enum variant, all
is_enabled()checks, and any dead branches. The codebase should not accumulate permanent flags. - Gate the UI entry point: if a flag hides a new UI surface, gate the entry point (button, menu item, panel) with the same flag so the feature is invisible when disabled.