Evaluation order
When your code calls getBooleanValue("checkout-v2", false, context), the SDK runs the following chain. Every feat SDK (Node, browser, Workers, Go, Python, Ruby) implements this identically, so the same datafile, context, and flag key always produce the same result and the same reason.
The chain
Section titled “The chain”1. Archived flag → off variation reason: DISABLED2. isEnabled is false → off variation reason: DISABLED3. Individual target → target's variation reason: TARGETING_MATCH4. First matching rule ├─ Rule serves variation → that variation reason: TARGETING_MATCH └─ Rule serves rollout → bucketed variation reason: SPLIT5. Default rule ├─ Single variation default → that variation reason: FALLTHROUGH └─ Default rollout → bucketed variation reason: SPLIT6. Nothing matched (rare) → off variation reason: DEFAULT7. Error (missing flag, etc.) → caller-supplied default reason: ERRORThe chain is short-circuit: as soon as one step decides, evaluation returns.
Per step
Section titled “Per step”1. Archived flag
Section titled “1. Archived flag”If the flag is archived, the SDK returns the off-variation immediately. reason is DISABLED. This lets your code keep calling an archived flag without panic; it just always returns the safe value.
2. isEnabled is false
Section titled “2. isEnabled is false”The flag’s per-environment toggle is off. SDK returns the off-variation with reason: DISABLED.
The off-variation is what you configure in the dashboard for the environment. For a kill switch, set it to the safe path.
3. Individual targeting
Section titled “3. Individual targeting”If the flag has individual targeting entries, the engine checks for an exact (contextKindKey, contextKey) match against the context.
- Multi-kind contexts are checked one kind at a time; the first match wins.
- A match returns the target’s variation with
reason: TARGETING_MATCH.
4. Targeting rules
Section titled “4. Targeting rules”The engine walks the rules in position order. For each rule:
- All conditions in a group are AND’d.
- All groups in a rule are OR’d.
- A condition whose attribute is missing in the context skips the rule (the rule does not match, evaluation moves on).
- If the rule matches:
- If
variationIdis set, return that variation withreason: TARGETING_MATCH. - If
rolloutis set, hash(targeting key on bucketing kind) + (flag key) + (per-flag salt)to a position in 1..100,000, pick the variation whose slice contains the position, return it withreason: SPLIT.
- If
If no rule matches, evaluation proceeds to step 5.
See Operators for the operator catalog and Percentage rollouts for the bucketing detail.
5. Default rule
Section titled “5. Default rule”Every environment config carries either:
- A
defaultVariationId: a single variation served when no rule matched.reason: FALLTHROUGH. - A
defaultRollout: a weighted split, same bucketing as rule rollouts.reason: SPLIT.
Exactly one of the two is set. The “default rule” is the catch-all the dashboard shows at the bottom of the rules list.
6. Nothing matched
Section titled “6. Nothing matched”If the default rule is malformed, the engine falls back to the off-variation with reason: DEFAULT. This step should not be reached in practice; it is the engine’s last-resort fallback.
7. Error
Section titled “7. Error”If the flag is missing from the datafile, the variation lookup fails, or any other unrecoverable error occurs, the SDK returns the caller-supplied default value (the second argument to getBooleanValue) with reason: ERROR. errorMessage carries a human-readable explanation.
Common causes:
- The flag was never created in this environment.
- The flag was deleted (not archived; archived flags hit step 1, not step 7).
- The variation an individual target or rule points to was deleted (should not happen; the API blocks variation deletion when references exist, but the engine handles it defensively).
Reason values, summarized
Section titled “Reason values, summarized”| Reason | What it means |
|---|---|
TARGETING_MATCH | An individual target or a deterministic rule matched. |
SPLIT | A percentage rollout (in a rule or in the default) decided. |
FALLTHROUGH | The default rule’s single variation was returned. |
DEFAULT | Engine fallback to off; rare. |
DISABLED | The flag is archived or targeting is off. |
ERROR | Something went wrong; the caller-supplied default was returned. |
Reference implementation
Section titled “Reference implementation”@feathq/feat-eval is the canonical engine in TypeScript. Every other SDK (Go, Python, Ruby) ports the same logic. If two SDKs disagree on a result for the same datafile and context, that is a bug.
Related
Section titled “Related”- Targeting rules for rule structure.
- Individual targeting for step 3.
- Percentage rollouts for the bucketing math.
- Operators for what each condition does.