FeatureFlipper

A comprehensive, easy-to-integrate feature flag system for Elixir applications with Consul integration, caching, and deadline management.

Features

  • Simple Configuration Interface: Easy setup with minimal configuration
  • Feature Definition DSL: Clean, declarative syntax for defining feature flags
  • Automatic Function Generation: Generates functions for each defined feature flipper
  • Environment-Aware Logic: Different behavior for production vs non-production environments
  • Consul Integration: Seamless integration with Consul KV store
  • Caching Layer: High-performance in-memory caching with :persistent_term
  • Configuration Management: Runtime configuration reloading
  • Deadline Management: Automatic deadline checking and warnings

Installation

Add feature_flipper to your list of dependencies in mix.exs:

def deps do
  [
    {:feature_flipper, "~> 0.1.0"}
  ]
end

Configuration

Add configuration to your config/config.exs:

config :feature_flipper,
  consul_kv_path: "telephony/services/routing",
  consul_client_http_addr: "http://consul.query.dev.telnyx.io:18500",
  env: System.get_env("ENV", "dev"),
  hostname: System.get_env("SERVER_HOSTNAME", "local"),
  cache_name: :feature_flipper_cache,
  version_suffix: "1.7.9-rc"  # Optional, for production versioning

Usage

1. Add it as a start phase

# lib/my_app/application.ex
def start_phase(:get_feature_flippers) do
  FeatureFlipper.ConfigLoader.init()
end

2. Define feature flippers

# lib/my_app/feature_flippers.ex
defmodule MyApp.FeatureFlippers do
  use FeatureFlipper.Definition

  define_flipper :use_warehouse_cache_tbs_2221?, %{
    deadline: ~D[2025-06-30],
    description: "Use warehouse cache for improved performance"
  }

  define_flipper :enable_warehouse_cache_mirroring_tbs_2395?, %{
    deadline: ~D[2025-06-30],
    force_disable: false,
    description: "Enable cache mirroring for data consistency"
  }

  define_flipper :user_rate_tariff_manager_tbs_2873?, %{
    deadline: ~D[2025-06-30],
    key: "custom_tariff_key",  # Optional custom Consul key
    description: "Use new tariff manager for user rates"
  }
end

3. Use feature flippers in your code

# Using generated functions (recommended)
if MyApp.FeatureFlippers.use_warehouse_cache_tbs_2221?() do
  # Feature is enabled
  use_warehouse_cache()
else
  # Feature is disabled
  use_regular_cache()
end

# Using the main interface
if FeatureFlipper.enabled?(:use_warehouse_cache_tbs_2221?) do
  # Feature is enabled
end

Environment Behavior

Non-production environments (dev, test, staging)

  • Features are enabled by default unless force_disable: true is set
  • Consul is not required to be available
  • Graceful fallback to default values

Production environment

  • Features are controlled by Consul KV data
  • Consul connectivity is required for accurate feature flag values
  • Supports hostname-specific feature flags

Consul Integration

Path Structure

The library automatically builds Consul paths based on your configuration:

  • Production: {consul_kv_path}/feature_flippers[_{version_suffix}]
  • Non-production: {consul_kv_path}/feature-flippers[_{version_suffix}]

Hostname Targeting

You can target specific hostnames by appending the hostname to the key:

# General key
my_feature_flag: true

# Hostname-specific key (takes precedence)
my_feature_flag_server1: false

Data Format

Consul values can be stored as:

  • JSON booleans: true, false
  • String booleans: "true", "false"

API Reference

Main Interface

# Check if a feature is enabled
FeatureFlipper.enabled?(:my_feature)
FeatureFlipper.enabled?("my_feature")

# Reload configuration from Consul
FeatureFlipper.reload_configuration()

# Get all feature flags and their values
FeatureFlipper.get_all_flags()

Definition Options

When defining feature flippers, you can specify:

  • :deadline - Date when the feature should be removed (Date struct)
  • :description - Human-readable description of the feature
  • :force_disable - Force disable in non-production environments (boolean, default: false)
  • :key - Custom Consul key (string, optional - defaults to the flipper name)

Deadline Management

TODO: This is not yet properly implemented

The library automatically tracks feature flipper deadlines:

# Check for overdue features
warnings = FeatureFlipper.check_deadlines()
# Returns: ["Feature 'old_feature' is past its deadline of 2024-01-01"]

# This can be integrated into your monitoring/alerting system

Error Handling

The library provides comprehensive error handling:

  • fail fast: fail fast if consul is not available
  • Invalid data: Graceful parsing with sensible defaults
  • Configuration errors: Clear error messages and logging

Performance

  • In-memory caching: Fast access to feature flag values
  • Minimal overhead: Efficient caching layer with :persistent_term
  • Batch loading: Loads all configuration at startup

Testing

The library includes comprehensive test coverage and provides mocking capabilities for testing your feature-flagged code.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.