0.0
The project is in a healthy, maintained state
Server-side SDK for evaluating feature flags with Featureflip
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 3.13
~> 3.23
~> 1.0

Runtime

>= 0
 Project Readme

Featureflip Ruby SDK

Ruby SDK for Featureflip - evaluate feature flags locally with near-zero latency.

Installation

Add to your Gemfile:

gem "featureflip"

Or install directly:

gem install featureflip

Quick Start

require "featureflip"

# Initialize the client (blocks until flags are loaded)
client = Featureflip::Client.get("your-sdk-key")

# Evaluate a feature flag
enabled = client.bool_variation("my-feature", { "user_id" => "user-123" }, false)

if enabled
  puts "Feature is enabled!"
else
  puts "Feature is disabled"
end

# Clean shutdown
client.close

Configuration

config = Featureflip::Config.new(
  base_url: "https://eval.featureflip.io",  # Evaluation API URL (default)
  streaming: true,                            # Use SSE for real-time updates (default)
  poll_interval: 30,                          # Polling interval in seconds
  send_events: true,                          # Enable analytics event tracking (default)
  flush_interval: 30,                         # Event flush interval in seconds
  flush_batch_size: 100,                      # Events per batch
  init_timeout: 10,                           # Max seconds to wait for initialization
  connect_timeout: 5,                         # HTTP connection timeout in seconds
  read_timeout: 10,                           # HTTP read timeout in seconds
  max_stream_retries: 5,                      # SSE retries before falling back to polling
)

client = Featureflip::Client.get("your-sdk-key", config: config)

The SDK key can also be set via the FEATUREFLIP_SDK_KEY environment variable.

To let a process that starts while the Evaluation API is unreachable serve its last known flags, pass snapshot_store: Featureflip::FileSnapshotStore.new("/path/to/snapshot.json") (and optionally max_snapshot_age_seconds:, default 86400). It is off unless you set it. See the Ruby SDK docs.

Singleton Convenience API

For applications that use a single client instance:

Featureflip.configure do |c|
  c.sdk_key = "your-sdk-key"
  c.base_url = "https://eval.featureflip.io"
  c.streaming = true
end

enabled = Featureflip.bool_variation("my-feature", { "user_id" => "123" }, false)

# On shutdown
Featureflip.close

Lifetime

Client.get returns handles backed by a shared core keyed by SDK key. Multiple calls with the same key share one set of connections and background threads:

client1 = Featureflip::Client.get("sdk-key")
client2 = Featureflip::Client.get("sdk-key")
# client1 and client2 share the same underlying resources

client1.close  # Resources still alive — client2 holds a reference
client2.close  # Now resources are cleaned up

This makes the SDK safe to use in dependency injection containers regardless of lifetime registration (singleton, scoped, or transient).

Evaluation

Context can use string or symbol keys:

context = { user_id: "123", email: "user@example.com" }
# or
context = { "user_id" => "123", "email" => "user@example.com" }

# Boolean flag
enabled = client.bool_variation("feature-key", context, false)

# String flag
tier = client.string_variation("pricing-tier", context, "free")

# Number flag
limit = client.number_variation("rate-limit", context, 100)

# JSON flag
config = client.json_variation("ui-config", context, { "theme" => "light" })

Detailed Evaluation

detail = client.variation_detail("feature-key", { user_id: "123" }, false)

detail.value          # The evaluated value
detail.reason         # "RuleMatch", "Fallthrough", "FlagDisabled", "FlagNotFound"
detail.rule_id        # Rule ID if reason is "RuleMatch"
detail.variation_key  # Key of the matched variation

Reacting to flag changes

unsubscribe = client.on_update do |changed_keys|
  Rails.logger.info("flags changed: #{changed_keys.join(', ')}")
end

unsubscribe.call # stop listening

The block runs on the SDK's streaming or polling thread, so keep it short. Hand real work to a queue. The initial flag load does not fire; only later changes do. Closing the client drops its subscriptions.

Event Tracking

# Track custom events
client.track("checkout-completed", { user_id: "123" }, { total: 99.99 })

# Record an identify event for analytics (does not affect flag evaluation)
client.identify({ user_id: "123", email: "user@example.com", plan: "pro" })

# Force flush pending events
client.flush

Featureflip counts each event name, per environment. The metadata you pass is transmitted with the event but is not stored, and event counts are not surfaced in the app or API.

Testing

Use the test client for deterministic unit tests with no network calls:

client = Featureflip::Client.for_testing(
  "my-feature" => true,
  "pricing-tier" => "pro"
)

client.bool_variation("my-feature", {}, false)      # => true
client.string_variation("pricing-tier", {}, "free")  # => "pro"
client.bool_variation("unknown", {}, false)           # => false (default)

Rails Setup

Featureflip is framework-agnostic. For Rails, initialize in an initializer:

# config/initializers/featureflip.rb
Featureflip.configure do |c|
  c.sdk_key = ENV["FEATUREFLIP_SDK_KEY"]
  c.streaming = true
end

# For Puma/Unicorn/Passenger — respawn threads after fork
# config/puma.rb
on_worker_boot do
  Featureflip.restart
end

Features

  • Local evaluation - Near-zero latency after initialization
  • Real-time updates - SSE streaming with automatic polling fallback
  • Event tracking - Automatic batching and background flushing
  • Test support - for_testing factory for deterministic unit tests
  • Thread-safe - Mutex-protected flag store and event queue
  • Fork-safe - restart method for Puma/Unicorn/Passenger worker processes
  • Zero runtime dependencies - Uses only Ruby stdlib (net/http, digest/md5)
  • OpenFeature - use the featureflip-openfeature provider

Requirements

  • Ruby 3.2+

Development

# Install dependencies
bundle install

# Run tests
bundle exec rspec

# Run specific test file
bundle exec rspec spec/featureflip/evaluation/evaluator_spec.rb

License

Apache-2.0