.ai/principles/distilled/feature-flags.md
default_enabled: false).config/initializers/* or at class level).Feature.current_request as actor with percentage-of-actors instead.group.root_ancestor as the actor when flag state must be consistent across an entire group hierarchy.Feature.enabled? for the same flag unless you are certain it won't cause inconsistent results within a request.:instance as the actor only when a feature is tied to an entire instance and no other actor type applies.Feature.enabled? and avoid Feature.get.~"feature flag" label to MRs that introduce, update state of, or remove a feature flag.rspec:feature-flags job)._mvc, _alpha, _beta in flag names.disable in flag names; prefer hide_, remove_, or disallow_ prefixes instead.bin/feature-flag (or bin/feature-flag --ee for EE-only).name, description, type, default_enabled, introduced_by_url, milestone, group.milestone value — read it from the VERSION file in the repo root and use the MAJOR.MINOR portion only (e.g., if VERSION contains 19.0.0-pre, set milestone: "19.0")default_enabled: false for gitlab_com_derisk, wip, and experiment types (setting it to true has no effect or is forbidden for these types).beta and ops type flags in the All feature flags in GitLab page.gitlab_com_derisk and beta flags..patch file alongside the YAML to enable automated removal via gitlab-housekeeper.gitlab_com_derisk for short-lived deployment de-risking flags (max 2 months lifespan).wip for hiding incomplete multi-MR features until fully implemented (max 4 months lifespan); transition to gitlab_com_derisk or beta before enabling.beta when a feature may have scalability concerns or is not yet a complete MVC (max 6 months lifespan).ops for long-lived operational control flags; evaluate every 12 months and update milestone to confirm continued use.experiment for A/B testing on GitLab.com (max 6 months lifespan); create rollout issue from the Experiment Rollout template.development type; use gitlab_com_derisk, wip, or beta instead.Feature.enabled? and Feature.disabled?.Project.actor_from_id(project_id) instead of Project.find(project_id) when the model is only needed for the feature flag check.experiment, worker, undefined types), pass type: explicitly to Feature.enabled?, Feature.disabled?, and push_frontend_feature_flag.push_frontend_feature_flag in a before_action scoped to a project or user actor.gon.features.vimBindings), not snake_case.other type).true — they are enabled by default in the test environment.stub_feature_flags(flag_name: false) to test the disabled state; place the stub in a before hook within a self-contained context.stub_feature_flags over Feature.enable* for test setup; use Feature.enable_percentage_of_time or Feature.enable_percentage_of_actors only when testing percentage rollout behavior.have_pushed_frontend_feature_flags matcher to verify push_frontend_feature_flag added the flag to HTML.stub_feature_flag_gate to create a custom actor for actor-specific flag testing in specs.stub_feature_flags: false unless specifically testing Flipper's interaction with ActiveRecord.experiment(:name, actor: current_user) as context but the corresponding issue mentions tracking of namespace-based activation events, assignment should happen based on namespace or actor + namespaceexperiment(:name, actor: current_user).track(:assignment, namespace: group)run_sidekiq_jobs_{WorkerName} (worker-type flag) to defer Sidekiq jobs during incidents; remove the flag after the worker is deemed safe.drop_sidekiq_jobs_{WorkerName} only when jobs are certain to not need future processing; note it takes precedence over run_sidekiq_jobs_{WorkerName}.ops flag to an application setting.default_enabled: from the feature flag YAML definition.Gitlab::Database::MigrationHelpers::FeatureFlagMigratorHelpers helpers in the migration; DO NOT use Feature.enabled? or Feature.disabled? inside migrations.For the full picture, see: