Skip to content

Feature Flags

feature_flags# Feature Flags

Overview

The Feature Flags module provides a powerful system for dynamically enabling or disabling features in your application at runtime, without requiring a code deployment. This is an essential tool for continuous delivery, A/B testing, and safely rolling out new functionality.

Key Features

  • Multiple Backends: Supports fetching flags from a local configuration dictionary, Redis, or Consul KV.
  • Declarative Usage: Protect an entire function or code path with the simple @feature_enabled decorator.
  • Contextual Evaluation: Flags can be evaluated based on the current ExecutionContext (e.g., enable a feature only for a specific tenant_id).
  • Multivariate Flags: Supports variants, which are flags that can return a string, number, or JSON object instead of just true/false.

How It Works

The system is orchestrated by the FeatureFlagFactory, which creates a provider instance based on your configuration. The primary way to interact with the system is through two utility functions: - is_feature_enabled(flag_key): Checks if a boolean flag is active. - get_feature_variant(flag_key): Retrieves the value of a multivariate flag.

For convenience, the @feature_enabled decorator wraps this logic, protecting an entire function.

Usage Example

from nala.athomic.control import feature_enabled, is_feature_enabled, get_feature_variant
from nala.athomic.context import context_vars

# --- Using the decorator ---
@feature_enabled(flag_key="new-dashboard-feature", context_kwargs=["tenant_id"])
async def show_new_dashboard(tenant_id: str):
    # This code will only run if the "new-dashboard-feature" is enabled.
    # The check can be contextual based on the tenant_id.
    return {"dashboard": "v2"}

# --- Using the utility functions ---
async def get_user_limit() -> int:
    # Get a variant value, with a default of 100
    limit = await get_feature_variant("user-concurrent-limit", default=100)
    return limit

Configuration

[default.control.feature_flags]
enabled = true
# The primary backend to fetch flags from.
backend = "consul"
# TTL in seconds for caching flags from external providers (Redis, Consul).
cache_ttl_seconds = 60

  [default.control.feature_flags.provider]
  backend = "consul"
  # The base path in Consul KV where flags are stored.
  kv_prefix = "config/flags"