Skip to content

Percentage rollouts

A percentage rollout sends a configured share of traffic to each variation. The same context always lands in the same bucket while the weights are unchanged, so a user does not flip between variations on every page load.

A rollout is one of the two possible results of:

  • A targeting rule: “for contexts matching X, split traffic 50/50 across variations A and B.”
  • The default rule for a flag in an environment: “for everyone no other rule matched, split traffic 10/90.”

You can have rollouts on multiple rules in the same flag, each with its own split.

For a given evaluation, feat computes a hash from:

  • The targeting key of the context (user-123), read off the chosen bucketing context kind.
  • The flag key (checkout-v2).
  • A hidden per-flag salt generated at flag creation.

The hash maps to a position in the range 1 to 100,000. Each variation gets a slice of that range proportional to its weight. The slice the hash falls into is the variation served.

Properties:

  • Stable. Same context plus same weights plus same flag means same variation, forever.
  • Independent per flag. Two flags with identical 50/50 rollouts will not co-bucket users. A user landing in the “on” bucket for flag A has no correlation with their bucket for flag B.
  • Cheap. Pure hashing. No state stored anywhere.

By default the rollout buckets on user. You can pick a different kind for any rollout:

  • Bucket by user for per-user rollouts. Two users in the same organization can land in different buckets.
  • Bucket by organization for per-customer rollouts. Everyone in a bucketed organization flips together.

The kind you pick must exist in the project. See Context kinds.

When you increase a rollout from 10% to 30%:

  • The original 10% stays bucketed to the same variation.
  • The newly included 20% are deterministically allocated based on the same hash.
  • Nobody in the original 10% flips out.

When you decrease a rollout, the reverse happens: the dropped slice flips back to the previously-served variation. This is the property that makes rollouts safe to nudge.

If you ever rotate the salt (rare; usually a dashboard action for restarting a rollout cleanly), every context re-buckets.

Default rule for checkout-v2 in production:
bucket by: user
variation true: 10%
variation false: 90%

A request comes in with targetingKey = "user-456". The SDK hashes "user-456" + "checkout-v2" + salt to position 73,212 in the 1-to-100,000 range. The true variation owns positions 1 to 10,000. The false variation owns 10,001 to 100,000. The user gets false.

You bump the weight to 30%. true now owns 1 to 30,000. Position 73,212 still falls in false. The user does not flip.

You bump again to 80%. true now owns 1 to 80,000. Position 73,212 is now in true. The user flips.

A percentage rollout is a deterministic split. It is not an experiment: feat does not track metrics against it or run a statistical test. If you need that layer (currently in scope for guarded rollouts; see the Progressive rollouts page for the related primitive), do not rely on a rollout for “is the new variant good.”