Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion docs/reference/sdks/client/dart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from dart-sdk.
Edits should be made here: https://github.com/open-feature/dart-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:08 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:30 GMT+0000 (Coordinated Universal Time)
-->

# OpenFeature Dart Client SDK
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/client/kotlin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from kotlin-sdk.
Edits should be made here: https://github.com/open-feature/kotlin-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
14 changes: 11 additions & 3 deletions docs/reference/sdks/client/swift.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from swift-sdk.
Edits should be made here: https://github.com/open-feature/swift-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down Expand Up @@ -122,7 +122,7 @@ The SDK is an abstraction layer, it holds the evaluation context and tracking ev
| ✅ | [MultiProvider](#multiprovider) | Combine multiple providers with configurable evaluation strategies. |
| ✅ | [InMemoryProvider](#inmemoryprovider) | Resolve flags from an in-memory configuration, for demos and testing. |
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
| ❌ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |

<sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>
Expand Down Expand Up @@ -445,7 +445,15 @@ let cancellable = OpenFeatureAPI.shared.observe().sink { event in

### Shutdown

A shutdown function is not yet available in the iOS SDK.
`OpenFeatureAPI.shared.shutdown()` calls the active provider's `shutdown` and resets the API — provider, hooks and evaluation context — so it can be configured again later; the logger is kept.
Use `shutdownAndWait()` when you need to know the provider has finished, for example to flush tracking data before the process exits:

```swift
await OpenFeatureAPI.shared.shutdownAndWait()
```

Providers are also shut down whenever they stop being used: `setProvider` shuts down the provider it replaces, and `clearProvider` shuts down the one it removes (`clearProviderAndWait` returns once that is done).
A provider that holds resources implements `shutdown() -> Future<Void, Never>` to release them and revert to `.notReady` — `ProviderStatusTracker.reset()` does the latter — and resolves the `Future` when it is done; providers with nothing to release inherit a no-op default.

## Extending

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/client/web/angular.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from js-sdk.
Edits should be made here: https://github.com/open-feature/js-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:30 GMT+0000 (Coordinated Universal Time)
-->

<p align="center" class="github-badges">
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/client/web/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from js-sdk.
Edits should be made here: https://github.com/open-feature/js-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/client/web/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from js-sdk.
Edits should be made here: https://github.com/open-feature/js-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/cpp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from cpp-sdk.
Edits should be made here: https://github.com/open-feature/cpp-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:08 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:30 GMT+0000 (Coordinated Universal Time)
-->

<p align="center" class="github-badges">
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/dart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from dart-sdk.
Edits should be made here: https://github.com/open-feature/dart-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:30 GMT+0000 (Coordinated Universal Time)
-->

**Release status:** The server SDK has regular, non-beta releases on
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/dotnet.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from dotnet-sdk.
Edits should be made here: https://github.com/open-feature/dotnet-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
6 changes: 3 additions & 3 deletions docs/reference/sdks/server/go.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from go-sdk.
Edits should be made here: https://github.com/open-feature/go-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand All @@ -20,8 +20,8 @@ import MCPInstall from '@site/src/partials/mcp-install';
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.7.0&color=yellow&style=for-the-badge" />
</a>

<a href="https://github.com/open-feature/go-sdk/releases/tag/v1.19.0">
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.19.0&color=blue&style=for-the-badge" />
<a href="https://github.com/open-feature/go-sdk/releases/tag/v1.20.0">
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.20.0&color=blue&style=for-the-badge" />
</a>

<br/>
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/java.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from java-sdk.
Edits should be made here: https://github.com/open-feature/java-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:28 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/javascript/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from js-sdk.
Edits should be made here: https://github.com/open-feature/js-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:28 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/javascript/nestjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This content has been automatically generated from js-sdk.
Edits should be made here: https://github.com/open-feature/js-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:28 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/php.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from php-sdk.
Edits should be made here: https://github.com/open-feature/php-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/sdks/server/python.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This content has been automatically generated from python-sdk.
Edits should be made here: https://github.com/open-feature/python-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:06 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:29 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';

Expand Down
103 changes: 86 additions & 17 deletions docs/reference/sdks/server/ruby.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ This content has been automatically generated from ruby-sdk.
Edits should be made here: https://github.com/open-feature/ruby-sdk
Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs

Last updated at Wed Oct 21 2026 11:43:07 GMT-0400 (Eastern Daylight Time)
Last updated at Fri Oct 30 2026 08:17:30 GMT+0000 (Coordinated Universal Time)
-->
import MCPInstall from '@site/src/partials/mcp-install';


<p align="center" class="github-badges">
<a href="https://github.com/open-feature/spec/releases/tag/v0.8.0">
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.8.0&color=yellow&style=for-the-badge" />
<a href="https://github.com/open-feature/spec/releases/tag/v0.9.0">
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.9.0&color=yellow&style=for-the-badge" />
</a>


<a href="https://github.com/open-feature/ruby-sdk/releases/tag/v0.6.5">
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.6.5&color=blue&style=for-the-badge" />
<a href="https://github.com/open-feature/ruby-sdk/releases/tag/v0.8.1">
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v0.8.1&color=blue&style=for-the-badge" />
</a>


Expand Down Expand Up @@ -82,7 +82,13 @@ OpenFeature::SDK.configure do |config|
config.set_provider(OpenFeature::SDK::Provider::InMemoryProvider.new(
{
"flag1" => true,
"flag2" => 1
"flag2" => 1,
# Variant flags report a variant and reason, and can target on the evaluation context
"flag3" => OpenFeature::SDK::Provider::InMemoryProvider::Flag.new(
variants: {"on" => true, "off" => false},
default_variant: "off",
context_evaluator: ->(ctx) { "on" if ctx&.targeting_key == "beta-user" }
)
}
))
end
Expand Down Expand Up @@ -161,9 +167,6 @@ rescue OpenFeature::SDK::ProviderInitializationError => e
puts "Original error: #{e.original_error}"
end

# With custom timeout (default is 30 seconds)
OpenFeature::SDK.set_provider_and_wait(my_provider, timeout: 60)

# Domain-specific provider
OpenFeature::SDK.set_provider_and_wait(my_provider, domain: "feature-flags")

Expand Down Expand Up @@ -288,6 +291,7 @@ Log output uses a structured key=value format:

Clients can be assigned to a domain. A domain is a logical identifier which can be used to associate clients with a particular provider.
If a domain has no associated provider, the default provider is used.
Clients look up their domain's provider on every call, so a client created before `set_provider` follows the new binding.

```ruby
OpenFeature::SDK.configure do |config|
Expand All @@ -301,28 +305,35 @@ legacy_flag_client = OpenFeature::SDK.build_client(domain: "legacy_flags")
### Eventing

Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions.
Initialization events (`PROVIDER_READY` on success, `PROVIDER_ERROR` on failure) are dispatched for every provider.
Some providers support additional events, such as `PROVIDER_CONFIGURATION_CHANGED`.
Providers emit initialization events (`PROVIDER_READY` on success, `PROVIDER_ERROR` on failure) from `init`.
A provider without `init` is `READY` as soon as it's registered, and its `PROVIDER_READY` handlers run before `set_provider` returns.
For providers that define `init` but not `emits_lifecycle_events?` returning `true`, the SDK emits `PROVIDER_READY` after `init` returns and `PROVIDER_ERROR` if it raises.
That path is deprecated (spec Appendix E), and the SDK logs a deprecation warning once per provider class to its configured logger.
Handlers for events a provider emits from `init` run while `init` is still in progress, so they can't call `set_provider_and_wait` for that same provider.
Some providers emit additional events: `PROVIDER_CONFIGURATION_CHANGED`, `PROVIDER_STALE`, `PROVIDER_RECONCILING` and `PROVIDER_CONTEXT_CHANGED`.
Handlers receive a hash with the `provider_name` and any details the provider sent, such as `message` or `error_code`.

Please refer to the documentation of the provider you're using to see what events are supported.

```ruby
# Register event handlers at the API (global) level
ready_handler = ->(event_details) do
puts "Provider #{event_details[:provider].metadata.name} is ready!"
puts "Provider #{event_details[:provider_name]} is ready!"
end

OpenFeature::SDK.add_handler(OpenFeature::SDK::ProviderEvent::PROVIDER_READY, ready_handler)

# The SDK automatically emits lifecycle events. Providers can emit additional spontaneous events
# using the EventEmitter mixin to signal internal state changes like configuration updates.
# Providers emit events using the EventEmitter mixin: lifecycle events from init, and spontaneous
# events to signal internal state changes like configuration updates.
class MyEventAwareProvider
include OpenFeature::SDK::Provider::EventEmitter

def emits_lifecycle_events? = true

def init(evaluation_context)
# Start background process to monitor for configuration changes
# Note: SDK automatically emits PROVIDER_READY when init completes successfully
start_background_process
emit_event(OpenFeature::SDK::ProviderEvent::PROVIDER_READY)
end

def start_background_process
Expand Down Expand Up @@ -352,6 +363,9 @@ This should only be called when your application is in the process of shutting d
OpenFeature::SDK.shutdown
```

The SDK also shuts down a replaced provider once no domain uses it.
Events from shut-down providers are ignored.

Individual providers can implement a `shutdown` method to perform cleanup:

```ruby
Expand Down Expand Up @@ -433,6 +447,29 @@ class MyRequestScopedPropagator
end
```

### Isolated API instances

`OpenFeature::SDK` is a global singleton. Some applications need more than one independent API in a process, for example separately developed modules that each need their own provider, or tests that run in parallel. Require the factory explicitly to create one:

```ruby
require "open_feature/sdk/isolated"

api = OpenFeature::SDK::Isolated.create_api
api.set_provider_and_wait(MyProvider.new)
client = api.build_client
client.fetch_boolean_value(flag_key: "my-flag", default_value: false)
```

Each instance has its own providers, hooks, evaluation context, event handlers, transaction context propagator and `shutdown`, and shares none of them with `OpenFeature::SDK` or other instances.
Build its clients with `api.build_client`; `OpenFeature::SDK::Client.new` binds to the global API.
Prefer the global API unless you need this.

A provider instance should be registered with only one API at a time.
Registering a provider that includes `OpenFeature::SDK::Provider::EventEmitter` with a second API raises `ArgumentError`; other providers can't be detected.
Once the first API replaces the provider or shuts down, it can be registered with another.

A `LoggingHook` created without `logger:` logs to the global API's logger, even when added to an isolated API. Pass `logger:` to use another.

## Extending

### Develop a provider
Expand All @@ -443,20 +480,46 @@ You’ll then need to write the provider by implementing the `Provider` duck.

```ruby
class MyProvider
def init
# Perform any initialization steps with flag management system here
include OpenFeature::SDK::Provider::EventEmitter

# Tells the SDK that init emits PROVIDER_READY/PROVIDER_ERROR itself.
def emits_lifecycle_events? = true

# Optional: a provider without init is READY as soon as it's registered.
# Both arguments are optional; declare only the ones you need.
# `domain` is the domain the provider was bound to, or nil for the default provider.
def init(evaluation_context = nil, domain: nil)
# Perform any initialization steps with flag management system here, then emit PROVIDER_READY.
# Return value is ignored
# **Note** The OpenFeature spec defines a lifecycle method called `initialize` to be called when a new provider is set.
# To avoid conflicting with the Ruby `initialize` method, this method should be named `init` when creating a provider.
emit_event(OpenFeature::SDK::ProviderEvent::PROVIDER_READY)
rescue => e
emit_event(OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, error_code: OpenFeature::SDK::Provider::ErrorCode::GENERAL, message: e.message)
raise
end

# Optional: return true if this provider keeps state for a single domain.
# The SDK then raises ArgumentError if the same instance is bound to a second domain.
def domain_scoped?
false
end

def shutdown
# Perform any shutdown/reclamation steps with flag management system here
# Return value is ignored
end

# Optional: hooks the SDK runs on every evaluation that uses this provider (spec 2.3.1).
# They run after API, client and invocation hooks in the before stage, and first in the after, error and finally stages.
def hooks
[]
end

def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
# Retrieve a boolean value from provider source
# To signal an error, return ResolutionDetails with an error_code, or raise
# OpenFeature::SDK::EvaluationError.new("message", error_code: OpenFeature::SDK::Provider::ErrorCode::FLAG_NOT_FOUND)
end

def fetch_string_value(flag_key:, default_value:, evaluation_context: nil)
Expand Down Expand Up @@ -513,5 +576,11 @@ class MyLoggingHook
end
```

Hooks can read the hook context and hints but not change them:

- Only `before` hooks can change the evaluation context: return an `EvaluationContext` for the SDK to merge in, or assign `hook_context.evaluation_context`. By the time `after`, `error` and `finally` run, it's a deep-frozen copy, so assigning it or changing its values raises `FrozenError`. Your own context isn't frozen.
- The flag key, the default value, the hints, and the client and provider metadata are frozen copies. Your own objects aren't frozen.
- Only the spec's value types are copied: strings, numbers, booleans, times, hashes and arrays. Other objects, such as a user or a record you put in the context, are passed to hooks as they are. A time is copied but left unfrozen, so `utc` and `localtime` still work, and a hash's default proc isn't copied.

> Built a new hook? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=hook&projects=&template=document-hook.yaml&title=%5BHook%5D%3A+) so we can add it to the docs!

Loading
Loading