Skip to main content

Identity-based value overrides, flag dependencies, and prerequisite chains for complex feature gating

Overrides & Prerequisites

Overrides and prerequisites add two powerful capabilities to flag evaluation: forcing specific values for individual users, and gating flags behind other flags.

Evaluation Order

With overrides and prerequisites, the full evaluation order becomes:

  1. Disabled check — if the flag is disabled, return default with DISABLED
  2. Overrides — identity match on targetingKey, highest priority wins
  3. Prerequisites — all prerequisite flags must evaluate to their expected values
  4. Targeting rules — evaluate conditions (with schedule gating)
  5. Variant selection — percentage-based variant assignment
  6. Default value — fallback with DEFAULT

Overrides take precedence over everything except the disabled check. Prerequisites are checked before targeting rules — if any prerequisite fails, the flag returns its default value.

Overrides

Overrides let you force a specific value for individual users, bypassing all targeting rules and variant logic. Common use cases:

  • QA testing — give testers the new experience without changing targeting rules
  • Incident response — force a user off a broken feature immediately
  • Customer support — enable a feature for a specific customer who reported an issue
  • Dogfooding — ensure internal team always sees new features

Defining Overrides

{
  "key": "checkout-v2",
  "enabled": true,
  "defaultValue": false,
  "overrides": [
    {
      "name": "QA Team",
      "description": "QA testers always see new checkout",
      "identifiers": ["qa-user-1", "qa-user-2", "qa-user-3"],
      "value": true,
      "priority": 10
    },
    {
      "name": "Blocked User",
      "description": "Customer experiencing issues",
      "identifiers": ["user-8472"],
      "value": false,
      "priority": 20
    }
  ],
  "targeting": [...]
}

Override Properties

PropertyTypeDescription
namestringHuman-readable name for this override group
descriptionstringOptional explanation of why this override exists
identifiersstring[]List of targetingKey values to match
valueanyThe value to return for matched users
prioritynumberHigher priority overrides are checked first

Priority Resolution

When a user matches multiple overrides, the highest priority override wins:

{
  "overrides": [
    { "name": "Global block", "identifiers": ["user-42"], "value": false, "priority": 1 },
    { "name": "VIP access", "identifiers": ["user-42"], "value": true, "priority": 10 }
  ]
}

User user-42 gets true because the VIP override (priority 10) outranks the global block (priority 1).

Override Evaluation Result

When an override matches, the evaluation returns:

{
  "value": true,
  "reason": "OVERRIDE"
}

When Overrides Don't Apply

  • Flag is disabledDISABLED always takes precedence
  • No targetingKey in context — overrides require a targeting key to match
  • Empty overrides array — falls through to prerequisites and targeting

Prerequisites

Prerequisites let you create flag dependencies — "Flag B is only evaluated if Flag A returns a specific value." This is useful for:

  • Feature gating chains — new checkout requires the payment API flag to be enabled
  • Staged rollouts — a feature depends on an infrastructure flag being active
  • Kill switches — disable a parent flag to cascade-disable all dependent features

Defining Prerequisites

{
  "key": "checkout-animations",
  "enabled": true,
  "defaultValue": false,
  "prerequisites": [
    {
      "flagKey": "checkout-v2",
      "expectedValue": true
    },
    {
      "flagKey": "animation-engine",
      "expectedValue": true
    }
  ],
  "targeting": [
    {
      "id": "all-users",
      "conditions": [
        { "property": "plan", "operator": "not_equals", "value": "free" }
      ],
      "value": true
    }
  ]
}

This flag (checkout-animations) only evaluates its targeting rules if both checkout-v2 and animation-engine evaluate to true.

Prerequisite Properties

PropertyTypeDescription
flagKeystringKey of the prerequisite flag
expectedValueanyValue the prerequisite must evaluate to

How Prerequisites Are Evaluated

  1. Each prerequisite flag is resolved using the same evaluation context
  2. The prerequisite flag goes through its own full evaluation (including its own prerequisites, if any)
  3. If the prerequisite's result doesn't match expectedValue, the dependent flag returns its default value with reason PREREQUISITE_FAILED
  4. All prerequisites must pass — they're evaluated with AND logic

Prerequisite Failure Response

{
  "value": false,
  "reason": "PREREQUISITE_FAILED"
}

If the prerequisite flag doesn't exist, the response includes error details:

{
  "value": false,
  "reason": "PREREQUISITE_FAILED",
  "errorCode": "FLAG_NOT_FOUND",
  "errorMessage": "Prerequisite flag 'checkout-v2' not found"
}

Recursive Prerequisites

Prerequisites are resolved recursively. If Flag C depends on Flag B, which depends on Flag A:

Flag A (no prerequisites) → evaluates normally
Flag B (requires Flag A = true) → checks A first
Flag C (requires Flag B = true) → checks B, which checks A

Flaggr handles this automatically via evaluateAsync(). Be careful not to create circular dependencies — a flag that depends on itself (directly or indirectly) will fail.

Sync vs Async Evaluation

Prerequisites require resolving other flags, which may involve storage lookups. Flaggr provides two evaluation paths:

MethodPrerequisitesUse case
FlagEvaluator.evaluate()Skipped (no async I/O)Hot-path client evaluation
FlagEvaluator.evaluateAsync()Fully resolvedServer-side API evaluation

Server-side API routes use evaluateAsync() automatically when a flag has prerequisites.

Combining Overrides and Prerequisites

The evaluation order ensures predictable behavior:

{
  "key": "premium-feature",
  "overrides": [
    { "name": "QA", "identifiers": ["qa-1"], "value": true, "priority": 10 }
  ],
  "prerequisites": [
    { "flagKey": "premium-backend", "expectedValue": true }
  ],
  "targeting": [...]
}
  • qa-1 always gets true via the override — prerequisites are not checked
  • Other users must pass the premium-backend prerequisite before targeting rules apply

This lets QA testers access features even when prerequisites aren't satisfied yet.

Best Practices

  • Keep prerequisite chains short — deep chains increase evaluation latency
  • Use overrides for temporary exceptions, not permanent targeting
  • Document override reasons in the description field
  • Review overrides periodically — stale overrides add noise and confusion
  • Name overrides after the purpose, not the person ("QA Testing" not "alice")
  • Don't use circular prerequisites — Flag A → Flag B → Flag A will fail