Appearance
Rules and contexts
A rule is the unit of conditional behavior on a flag, config, or segment. The evaluator walks rules top-to-bottom and returns the first one whose condition matches the current context.
A context is the bag of attributes you pass when evaluating: the user ID, the plan tier, the country code, the locale, the build version — anything you want to target on. Context shape is up to you; the only required field is the project's target ID (default userId), used for percentage-rollout stickiness.
Anatomy of a rule
json
{
"if": {
"$and": [
{ "field": "plan", "$equals": "enterprise" },
{ "field": "country", "$in": ["US", "CA"] }
]
},
"value": true,
"rolloutPercent": 50,
"description": "EU enterprise — 50% rollout"
}Three pieces:
if— a condition tree. See operators below.value— what the flag/config returns if this rule matches and the percent gate (if any) admits the caller.rolloutPercent(optional) — admit only N% of matching contexts. The percent gate is sticky: the same context always lands on the same side of the cut for the same rule.
A description is optional and surfaces in the dashboard and audit log.
Conditions
A condition is either a leaf (one field, one operator, one comparand) or a boolean combinator ($and / $or / $not over child conditions). Trees are bounded in depth to keep evaluation fast and predictable.
Leaf operators
Compare a single field from the context to a literal value:
| Operator | Meaning | Example |
|---|---|---|
$equals / $notEquals | Strict equality. | { "field": "plan", "$equals": "pro" } |
$in / $notIn | Membership in a literal array. | { "field": "country", "$in": ["US","CA"] } |
$gt / $gte / $lt / $lte | Numeric or lexicographic compare. | { "field": "buildVersion", "$gte": "5.2.0" } |
$startsWith / $endsWith / $contains | Substring matching on strings. | { "field": "email", "$endsWith": "@example.com" } |
$matches | Full-string regex match. RE2 syntax, portable subset. | { "field": "email", "$matches": "^admin\\+.+@example\\.com$" } |
$exists | Field is present in context. | { "field": "promoCode", "$exists": true } |
The regex dialect is RE2 with a portable subset enforced — features that vary across regex engines (lookaround, backreferences) are rejected at save time, so the rule behaves identically in the dashboard's preview, the server, and any future client-side evaluation. There's a dedicated POST /api/v1/validate/regex endpoint the rule builder calls on keystroke.
Boolean combinators
json
{
"$or": [
{ "$and": [ {"field": "plan", "$equals": "pro"},
{"field": "country", "$in": ["US","CA"]} ] },
{ "field": "email", "$endsWith": "@example.com" }
]
}$and and $or take an array of child conditions. $not takes a single child. Empty $and matches everything; empty $or matches nothing.
Segment references
json
{ "$segment": "beta_testers" }…matches if the caller is in the named segment. See Segments.
Percentage rollouts
rolloutPercent admits only N% of matching contexts. Stickiness is hashed:
admit = xxhash64(rule.id + ":" + context[targetIdField]) mod 10000 < rolloutPercent * 100The same context always lands on the same side of the cut for the same rule. Increasing the percent only ever admits more contexts; never re-shuffles anyone already admitted. That makes "10% → 25% → 50% → 100%" a smooth ramp rather than a re-roll.
Each rule has its own salt (the rule's UUID), so two flags running independent 50% rollouts at the same time aren't correlated — a user in the upper half of one flag is independently in either half of the other.
The target ID field defaults to userId and can be changed at the org or project level. If the context lacks the target ID field, percentage-gated rules don't admit and evaluation falls through to the next rule (or the default).
Evaluation order
Rules are checked in order. The first rule whose if matches AND whose rolloutPercent admits the caller wins; its value is returned. If no rule matches, the default value is returned.
The structured reason returned alongside the value names the winning rule (or default if none matched), the rule index, and the matched value. See Evaluation.
See also
- Evaluation — how the evaluator runs and what it returns.
- Segments — the
$segmentoperator in depth. - API reference: Evaluation — wire shapes, validation helpers, the spot-check preview endpoint.