Feature Flag Targeting Service: Low Level Design
A feature flag targeting service lets teams release features safely by controlling visibility per user, segment, or percentage of traffic. The design covers data modeling, rule evaluation, SDK behavior, caching, and streaming updates.
Data Model
FeatureFlag Table
FeatureFlag
-----------
id BIGINT PRIMARY KEY
key VARCHAR UNIQUE NOT NULL
description TEXT
type ENUM('boolean','string','number','json')
default_value TEXT
enabled BOOL NOT NULL DEFAULT false
created_at TIMESTAMP
TargetingRule Table
TargetingRule
-------------
id BIGINT PRIMARY KEY
flag_id BIGINT REFERENCES FeatureFlag(id)
priority INT NOT NULL
conditions JSONB
variation_value TEXT
rollout_pct INT CHECK (rollout_pct BETWEEN 0 AND 100)
Rules are ordered ascending by priority. The first rule whose conditions match the evaluation context wins.
Override Table
Override
--------
id BIGINT PRIMARY KEY
flag_id BIGINT REFERENCES FeatureFlag(id)
user_id VARCHAR NOT NULL
variation_value TEXT
UNIQUE (flag_id, user_id)
Rule Evaluation Algorithm
Evaluation Order
evaluate(flag_key, context):
1. Check Override table for (flag_id, context.user_id) → return if found
2. If flag.enabled == false → return flag.default_value
3. Load TargetingRules WHERE flag_id = flag.id ORDER BY priority ASC
4. For each rule:
if match_conditions(rule.conditions, context):
if rule.rollout_pct == 100: return rule.variation_value
bucket = hash(flag_key + context.user_id) mod 100
if bucket < rule.rollout_pct: return rule.variation_value
5. Return flag.default_value
Condition Attributes
Supported context keys for conditions: user_id, email, country, plan, and arbitrary custom attributes passed in the evaluation context object. Conditions are stored as JSONB and support operators: eq, neq, in, not_in, contains, semver_gte.
Sticky Bucketing
hash(flag_key + user_id) mod 100 is deterministic — the same user always lands in the same bucket for a given flag, producing consistent variation assignment across sessions without storing state.
SDK Design
Initialization
// Client fetches all flag configs for the user context on session start
GET /sdk/flags?context={user_id, country, plan, ...}
→ returns map of flag_key → variation_value (pre-evaluated server-side)
Local Evaluation
After bootstrap, the SDK caches flag configs in memory and evaluates locally on each isEnabled(flag_key) call — no network round-trip per evaluation. The SDK re-fetches on SSE update events.
Caching
Layer Store TTL Key
Flag config Redis 30s flags:{flag_key}
All flags Redis 30s flags:all
Per-user eval Local session flags:{flag_key}:u:{user_id}
On flag update, the service publishes an invalidation event that clears the Redis key immediately rather than waiting for TTL expiry.
Streaming Updates
GET /sdk/stream (SSE endpoint)
→ event: flag_updated
data: {flag_key, new_variation_values}
Connected SDKs receive flag changes within under 1 second. The server pushes events over Server-Sent Events (SSE); the SDK re-evaluates affected flags and updates its local cache.
Audit Log
AuditLog
--------
id BIGINT PRIMARY KEY
flag_id BIGINT
actor_id VARCHAR
action VARCHAR -- 'created','updated','deleted','toggled'
old_value JSONB
new_value JSONB
occurred_at TIMESTAMP
Every flag mutation (create, update, enable/disable, rule change) writes an immutable audit record. This supports compliance and rollback investigations.
Exposure Analytics
ExposureEvent
-------------
flag_key VARCHAR
variation TEXT
user_id VARCHAR
exposed_at TIMESTAMP
SDK fires an exposure event on first evaluation of each flag per session. Events are batched and flushed to a stream (e.g., Kafka) for downstream analysis — exposure counts, variation distribution, and funnel correlation.
Kill Switch
Setting enabled = false on a flag immediately returns default_value for all users, bypassing all rules. This is the fastest path to disable a feature in production without a code deployment.
Scale Considerations
- Flag config is read-heavy — Redis handles evaluation cache; write path is rare.
- SSE connections are long-lived; use a dedicated fan-out service (e.g., pub/sub) to push to thousands of connected SDK instances.
- Override table lookups use a composite index on
(flag_id, user_id)for O(1) lookups. - Exposure event ingestion uses async batching to avoid blocking flag evaluation.
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “What is a feature flag targeting service?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “A feature flag targeting service controls which users see a feature by evaluating targeting rules against user attributes such as country, plan, or user ID. It enables safe deployments, percentage rollouts, and instant kill switches without code redeployment.”
}
},
{
“@type”: “Question”,
“name”: “How does percentage rollout work in a feature flag system?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Percentage rollout uses a deterministic hash of the flag key and user ID modulo 100 to assign each user to a bucket. If the user's bucket number is less than the rollout percentage, they receive the treatment variation. This ensures the same user always gets the same variation — a property called sticky bucketing.”
}
},
{
“@type”: “Question”,
“name”: “What is sticky bucketing in feature flags?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Sticky bucketing ensures a user always sees the same variation for a given flag across sessions. It is achieved by hashing the flag key and user ID deterministically, so no session state needs to be stored. The same inputs always produce the same bucket assignment.”
}
},
{
“@type”: “Question”,
“name”: “How are feature flag changes pushed to SDKs in real time?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Connected SDKs maintain a Server-Sent Events (SSE) connection to a streaming endpoint. When a flag is updated, the server publishes a flag_updated event with the new configuration. SDKs receive this within under one second and refresh their local cache without requiring a full re-fetch.”
}
}
]
}
See also: Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering
See also: Anthropic Interview Guide 2026: Process, Questions, and AI Safety