Context and Overrides

Replane’s override system allows you to return different config values based on runtime context. This enables powerful use cases like feature flags, A/B testing, and gradual rollouts.

How Overrides Work

Each config in Replane has:

  • A base value - the default returned when no overrides match

  • Override rules - conditions that, when matched, return a different value

Override rules are evaluated in order. The first matching rule wins.

Config: "rate_limit"
├── Base value: 100
└── Overrides:
    ├── 1. If plan == "enterprise" → 10000
    ├── 2. If plan == "pro" → 1000
    └── 3. If region in ["us", "eu"] → 500

Using Context

Use with_context() to evaluate overrides:

# Without context - returns base value
rate_limit = replane.configs["rate_limit"]  # 100

# With context - evaluates overrides
pro_client = replane.with_context({"plan": "pro"})
rate_limit = pro_client.configs["rate_limit"]  # 1000

enterprise_client = replane.with_context({"plan": "enterprise"})
rate_limit = enterprise_client.configs["rate_limit"]  # 10000

Context Properties

Context is a dictionary with string keys and primitive values:

context = {
    # String values
    "user_id": "user-123",
    "plan": "premium",
    "region": "us-east",
    "country": "US",

    # Numeric values
    "age": 25,
    "purchase_count": 10,
    "account_age_days": 365,

    # Boolean values
    "is_admin": True,
    "is_beta_tester": False,
    "email_verified": True,

    # None is also valid (treated as "unknown")
    "referral_code": None,
}

Default Context

Set a default context that applies to all config accesses:

replane = Replane(
    ...,
    context={
        "environment": "production",
        "app_version": "2.1.0",
    },
)

# These accesses include the default context
replane.configs["feature"]  # context: {"environment": "production", "app_version": "2.1.0"}

# Additional context is merged with defaults using with_context()
user_client = replane.with_context({"user_id": "123"})
user_client.configs["feature"]
# Effective context: {"environment": "production", "app_version": "2.1.0", "user_id": "123"}

Condition Types

Replane supports several condition types for overrides:

Equals

Match when a property equals a specific value:

# Override: plan equals "premium"
replane.with_context({"plan": "premium"}).configs["feature"]  # Matches
replane.with_context({"plan": "free"}).configs["feature"]     # Doesn't match

In / Not In

Match when a property is (or isn’t) in a list of values:

# Override: plan in ["pro", "enterprise"]
replane.with_context({"plan": "pro"}).configs["feature"]        # Matches
replane.with_context({"plan": "enterprise"}).configs["feature"] # Matches
replane.with_context({"plan": "free"}).configs["feature"]       # Doesn't match

Comparison (lt, lte, gt, gte)

Numeric comparisons:

# Override: age >= 18
replane.with_context({"age": 21}).configs["adult_content"]  # Matches
replane.with_context({"age": 15}).configs["adult_content"]  # Doesn't match

Segmentation (Percentage Rollout)

Roll out features to a percentage of users:

# Override: 10% of users (based on user_id)
user_client = replane.with_context({"user_id": "user-123"})
user_client.configs["new_checkout"]
# Deterministic: same user always gets same result

Segmentation uses a hash function to deterministically bucket users. This ensures:

  • The same user always sees the same variant

  • Distribution is statistically uniform

  • No server-side state is needed

Logical Operators (AND, OR, NOT)

Combine conditions with logical operators:

# Override: (plan == "pro" OR plan == "enterprise") AND region == "us"
replane.with_context({"plan": "pro", "region": "us"}).configs["feature"]      # Matches
replane.with_context({"plan": "pro", "region": "eu"}).configs["feature"]      # Doesn't match
replane.with_context({"plan": "free", "region": "us"}).configs["feature"]     # Doesn't match

Client-Side Evaluation

All override evaluation happens locally in your application. The context you provide never leaves your servers.

This design provides:

  • Privacy - User data stays in your application

  • Speed - No network round-trip for config reads

  • Reliability - Works even if connection is temporarily lost

Common Patterns

Feature Flags

user_client = replane.with_context({"user_id": user.id})
if user_client.configs["new_dashboard_enabled"]:
    return render_new_dashboard()
else:
    return render_old_dashboard()

Plan-Based Features

plan_client = replane.with_context({"plan": user.plan})
max_projects = plan_client.configs["max_projects"]
# free: 3, pro: 10, enterprise: unlimited (-1)

Gradual Rollout

Configure a 10% rollout in Replane dashboard, then:

user_client = replane.with_context({"user_id": user.id})
use_new_algorithm = user_client.configs["new_recommendation_algorithm"]

Geographic Targeting

geo_client = replane.with_context({"country": request.geo.country})
banner_content = geo_client.configs["homepage_banner"]

A/B Testing

user_client = replane.with_context({"user_id": user.id})
button_color = user_client.configs["checkout_button_color"]
# Returns "blue", "green", or "red" based on user's bucket

Missing Context Properties

When a condition references a property not in the context:

  • The condition result is “unknown”

  • For AND conditions: if any condition is unknown and none fail, the result is unknown

  • For OR conditions: if any condition matches, it matches; otherwise unknown

  • Unknown results typically mean the override doesn’t match

# Override requires "plan" property
replane.configs["feature"]  # Override won't match (no plan in default context)
replane.with_context({"plan": "pro"}).configs["feature"]  # Override can match

Best practice: ensure your context includes all properties that overrides might reference.