Percentage rollouts
Deterministic, cross-language rollout bucketing.
A percentage rollout enables a flag for a deterministic fraction of your users — 10% first, then 25%, then everyone — without code changes. It's how you ramp a feature safely.
Setting a rollout
Each flag-environment has a rollout_pct. Think of it as the fallthrough:
when the flag is enabled and a user matches no targeting rule, the rollout decides
whether they get the enabled value.
rollout_pct = 25→ roughly 25% of users get the flag.rollout_pct = 0→ nobody gets it via the rollout (rule matches still do).rollout_pct = 100→ everyone gets it.- unset (no rollout configured) → the default for a new flag — see the note below for how it resolves.
Deterministic bucketing
A user is bucketed by hashing their user_id together with the flag key:
bucket = sha256("{user_id}:{flag_key}") % 100user is in the rollout if bucket < rollout_pct
Two consequences fall out of this:
- Stable per user. The same user always lands in the same bucket for a given flag, so they don't flicker between on and off across requests or page loads. User "42" either always sees the feature at 25% or never does.
- Stable as you ramp. Because the bucket doesn't depend on the percentage, everyone in the 10% cohort is still included when you go to 25% — you only ever add users as you increase the percentage, never reshuffle them.
A user_id (or id) is required for rollouts. With no user context, a flag at
less than 100% can't bucket the caller, so it falls back to the default value.
Identical across languages
The hashing is part of the cross-language SDK contract: Python and JavaScript
compute the same bucket for the same user_id:flag_key. A user bucketed into
the 25% cohort gets the feature whether your backend (Python) or your frontend
(JavaScript) does the check. This parity is pinned by a shared set of test vectors
that both SDKs run.
The "no rollout configured" default
A new flag-environment starts with no rollout configured, and what that means depends on whether you've added targeting rules:
- No rules, no rollout → the flag is a plain on/off switch: enabled serves everyone, disabled serves no one.
- Rules, no rollout → only the users who match a rule get the flag; the fallthrough is effectively 0%. Adding a rule narrows the audience to exactly that rule — it doesn't leak to everyone else.
- Rules + a rollout → rule matchers always get it, plus the rollout percentage of everyone else.
Internally "no rollout configured" is stored as a null rollout_pct. With no
rules it resolves to 100 (everyone); with rules present the backend publishes it
as a 0% fallthrough so the rules actually scope the audience. The dashboard shows
the rollout slider once you deliberately set a percentage — and you can set it
to a full 100% (an explicit "serve everyone," distinct from leaving it unset).
(See ADR-008 for the reasoning and the resolution rule — the SDKs read the
resolved number, so the evaluator itself stays a simple bucket < rollout_pct
check.)
Next
- Evaluation order — how rules and rollout interact, step by step.
- Targeting rules — enable for specific users regardless of the rollout.