Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 210 additions & 1 deletion content/en/feature_flags/server/ruby.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,217 @@ Feature Flags are in Preview. Complete the form to request access.

This page describes how to instrument your Ruby application with the Datadog Feature Flags SDK.

Documentation coming soon.
## Prerequisites

Before setting up the Ruby Feature Flags SDK, ensure you have:

- **Datadog Agent** with [Remote Configuration][1] enabled
- **Datadog Ruby tracer** `datadog` version 2.23.0 or later
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet published. Assuming this will be in the next minor release https://github.com/DataDog/dd-trace-rb/releases

- **OpenFeature Ruby SDK** `openfeature-sdk` version 0.4.1 or later
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

- **Service and environment configured** - Feature flags are targeted by service and environment

## Installing and initializing

Feature Flagging is provided by APM. To integrate APM into your application with feature flagging support, install the required gems and configure remote configuration with OpenFeature support.

```shell
gem install ddtrace openfeature-sdk
```

```ruby
require 'datadog'
require 'open_feature/sdk'
require 'datadog/open_feature/provider'

# Configure Datadog with feature flagging enabled
Datadog.configure do |config|
config.remote.enabled = true
config.open_feature.enabled = true
end

# Configure OpenFeature SDK with Datadog provider
OpenFeature::SDK.configure do |config|
config.set_provider(Datadog::OpenFeature::Provider.new)
end

# Create OpenFeature client
client = OpenFeature::SDK.build_client
```

The client returns default values until remote configuration loads in the background. This approach keeps your application responsive during startup but may serve defaults for early requests.
Copy link
Author

@sameerank sameerank Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provider eventing is not yet supported in OpenFeature: https://github.com/open-feature/ruby-sdk?tab=readme-ov-file#eventing

Eventing is needed for proper separation of non-blocking-vs-blocking between set_provider vs set_provider_and_wait so I'm leaving that out of the docs for now. I'm currently working on a pull request to get OpenFeature's set_provider_and_wait to match the event-based OpenFeature spec and then I can add a section for the blocking version of setting the provider to this doc (which is likely a common use-case)


## Set the evaluation context

Define an evaluation context that identifies the user or entity for flag targeting. The evaluation context includes attributes used to determine which flag variations should be returned:

```ruby
context = OpenFeature::SDK::EvaluationContext.new(
targetingKey: 'user-123', # Targeting key (typically user ID)
email: '[email protected]',
country: 'US',
tier: 'premium',
age: 25
)
```

The targeting key is used for consistent traffic distribution (percentage rollouts). Additional attributes enable targeting rules such as "enable for users in the US" or "enable for premium tier users."

## Evaluating flags

After creating the `OpenFeature` client, you can start reading flag values throughout your app. Flag evaluation uses locally cached data, so no network requests occur when evaluating flags.

Each flag is identified by a unique string _key_. Flags are evaluated using typed methods that return values matching the expected type. The SDK returns the default value if a flag doesn't exist or cannot be evaluated.

### Boolean flags

Use `fetch_boolean_value()` for flags that represent on/off or true/false conditions:

```ruby
enabled = client.fetch_boolean_value(
flag_key: 'new-checkout-flow',
default_value: false,
evaluation_context: context
)

if enabled
show_new_checkout
else
show_legacy_checkout
end
```

### String flags

Use `fetch_string_value()` for flags that select between multiple variants or configuration strings:

```ruby
theme = client.fetch_string_value(
flag_key: 'ui-theme',
default_value: 'light',
evaluation_context: context
)

case theme
when 'dark'
set_dark_theme
when 'light'
set_light_theme
else
set_light_theme
end
```

### Number flags

For numeric flags, use `fetch_integer_value()` or `fetch_float_value()`. Ruby also provides `fetch_number_value()` which returns the appropriate type based on the default value. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier:

```ruby
max_items = client.fetch_integer_value(
flag_key: 'cart-max-items',
default_value: 20,
evaluation_context: context
)

discount_rate = client.fetch_float_value(
flag_key: 'discount-rate',
default_value: 0.0,
evaluation_context: context
)

# Generic number method (type based on default)
batch_size = client.fetch_number_value(
flag_key: 'batch-size',
default_value: 100, # Returns integer
evaluation_context: context
)
```

### Object flags

For structured data, use `fetch_object_value()`. This method returns a hash. Object flags are useful for remote configuration scenarios where multiple properties need to be provided together.

```ruby
config = client.fetch_object_value(
flag_key: 'feature-config',
default_value: {
'maxRetries' => 3,
'timeout' => 30
},
evaluation_context: context
)

max_retries = config['maxRetries'] || 3
timeout = config['timeout'] || 30
```

### Flag evaluation details

When you need more than the flag value, use the `fetch_<type>_details` methods. These methods return both the evaluated value and metadata explaining the evaluation:

```ruby
details = client.fetch_boolean_details(
flag_key: 'new-feature',
default_value: false,
evaluation_context: context
)

puts "Value: #{details.value}"
puts "Variant: #{details.variant}"
puts "Reason: #{details.reason}"
puts "Error Code: #{details.error_code}"
puts "Error Message: #{details.error_message}"
```

Flag details help you debug evaluation behavior and understand why a user received a given value.

## Evaluation without context

You can evaluate flags without providing an evaluation context. This is useful for global flags that don't require user-specific targeting:

```ruby
# Global feature flag - no context needed
maintenance_mode = client.fetch_boolean_value(
flag_key: 'maintenance-mode',
default_value: false
)

if maintenance_mode
halt 503, { error: 'Service temporarily unavailable' }.to_json
end
```

## Troubleshooting

### Feature flags surprisingly always return default values

If feature flags always return default values:

1. Verify Remote configuration is enabled in your Datadog Agent configuration
2. Ensure service and environment are configured (either through `DD_SERVICE`/`DD_ENV` environment variables or `config.service`/`config.env` in Ruby)
3. Check that `config.remote.enabled = true` and `config.open_feature.enabled = true` are set in your Ruby application's Datadog configuration
4. Verify the datadog gem version includes OpenFeature support (2.23.0 or later)

### Remote configuration connection issues

Check the Datadog tracer logs for Remote configuration status:

```ruby
# Enable startup and debug logging
Datadog.configure do |config|
config.diagnostics.startup_logs.enabled = true
config.diagnostics.debug = true
config.remote.enabled = true
config.open_feature.enabled = true
end
```

Look for messages about:
- Remote Configuration worker starting
- Feature flags configuration being received
- OpenFeature component initialization

## Further reading

{{< partial name="whats-next/whats-next.html" >}}

[1]: /agent/remote_config/
Loading