Skip to main content
Warp uses a lightweight feature flag system to control which behaviors are active in different build configurations. Flags are defined as variants on the 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 single FeatureFlag 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.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Sequence)]
pub enum FeatureFlag {
    // Infrastructure
    Autoupdate,
    CrashReporting,
    DebugMode,
    RuntimeFeatureFlags,

    // Drive and sharing
    CloudObjects,
    CreatingSharedSessions,
    ViewingSharedSessions,
    SharedWithMe,
    SessionSharingAcls,
    SharedSessionWriteToLongRunningCommands,

    // AI and Agent Mode
    AgentMode,
    AgentModeWorkflows,
    AgentModeAnalytics,
    AgentPredict,

    // … 100+ additional variants
}
Each variant maps to an 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:
Enabled only in local debug builds. Used for low-level diagnostics that should never reach any users.
pub const DEBUG_FLAGS: &[FeatureFlag] = &[
    FeatureFlag::DebugMode,
    FeatureFlag::RuntimeFeatureFlags,
];

How to add a new flag

1

Add the variant to FeatureFlag

Open crates/warp_features/src/lib.rs and add your variant to the FeatureFlag enum. Add a doc comment explaining what the flag gates:
/// Enables the new branch history sidebar.
BranchHistorySidebar,
Add it near related flags for readability, but do not reorder existing variants — their array indices are load-bearing.
2

Optionally add to a rollout array

Add the variant to DOGFOOD_FLAGS if you want it on by default for internal builds, or to PREVIEW_FLAGS for preview users:
pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
    // … existing flags …
    FeatureFlag::BranchHistorySidebar,
];
Skip this step if you want the flag off everywhere by default (e.g., for a server-controlled experiment that is toggled via set_enabled).
3

Gate code paths with is_enabled()

Use FeatureFlag::YourFlag.is_enabled() at each gated call site:
if FeatureFlag::BranchHistorySidebar.is_enabled() {
    // show the sidebar entrypoint
}
For UI components, gate the entire component’s construction:
if FeatureFlag::BranchHistorySidebar.is_enabled() {
    elements.push(BranchHistorySidebar::render(ctx));
}
4

Add a flag description (Preview-only)

If the flag is in PREVIEW_FLAGS and you want it to appear in the Preview changelog, add a match arm in flag_description():
BranchHistorySidebar => {
    Some("Enables the branch history sidebar for quick navigation between recent branches.")
}

Checking flag state

// Check whether a flag is currently enabled
if FeatureFlag::CreatingSharedSessions.is_enabled() {
    show_share_button(ctx);
}
is_enabled() resolves state in priority order:
  1. Thread-local test override (if set via override_enabled)
  2. User preference (set via set_user_preference, e.g. from a UI toggle)
  3. 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 a ServerExperiment 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, use override_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:
#[cfg(test)]
mod tests {
    use warp_features::FeatureFlag;

    #[test]
    fn test_share_button_visibility() {
        // Enable the flag for this test only
        let _guard = FeatureFlag::CreatingSharedSessions.override_enabled(true);

        // … run assertions …
    } // _guard dropped here; flag reverts to its previous state
}
override_enabled is only available when the test-util feature is enabled on the warp_features crate. Do not use set_enabled in unit tests — it mutates global state and can cause interference between parallel tests.

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.

Build docs developers (and LLMs) love