Skip to main content
The openfeature/ sub-module wraps an initialized *nexus.Client in an OpenFeature provider. It is published as a separate Go module so you only pull in the OpenFeature SDK dependency if you need it.

Installation

Install both the core SDK and the provider sub-module:

Usage

Evaluation mapping

Boolean evaluation is per-user when the EvaluationContext carries a targeting key. The flag is resolved through the AB Testing add-on, so its rollout percentage and cohort rules apply to that identity. Without a targeting key the synced snapshot is read.

Per-user targeting

Cohort attribute values are compared as strings, so pass strings: a non-string context attribute is left out of the evaluation and reported through the provider’s logger. Format the value at the call site - strconv.Itoa(age) rather than age - and you know exactly what the cohort rule is matched against. Only boolean evaluation is targeted. String, float, int and object values come from configs, and a config has no per-user dimension in Nexus.

Requests and caching

A targeted evaluation is a network call where the snapshot path is a map read. Two things keep that affordable, and neither needs configuring: one request serves every flag the snapshot knows for that user, so reading five flags while handling a request costs one round trip; and results are memoised per user and flag for 30 seconds, with concurrent evaluations for the same user coalescing into a single request. Adjust the window with WithTargetingTTL, bound how many users are held with WithMaxTargetingKeys, and give the provider a logger with WithLogger.

Reason codes

A failed targeted request never surfaces as an error. The OpenFeature SDK answers an error resolution by returning the caller’s default, so a flag that is genuinely on would evaluate off because of one failed request; the snapshot value with a STALE reason is the honest answer and the better one. A project without the AB Testing add-on gets STATIC from the snapshot, and the provider stops asking for five minutes before trying again. SPLIT is never reported: the endpoint returns booleans only, so a rollout bucket and a cohort match are indistinguishable here, and TARGETING_MATCH covers both.

Behavior notes

  • Boolean flags resolve a feature flag. All other types use GetConfig. A flag that is not in the snapshot produces FLAG_NOT_FOUND with your default value, so a mistyped flag key is distinguishable from a flag deliberately turned off.
  • JSON number types. Config values arrive as json.Number, the exact decimal text off the wire. IntEvaluation converts with Int64(), so a fractional or out-of-range value returns TYPE_MISMATCH rather than being truncated - 3.7 is not 3. FloatEvaluation uses Float64(). Both also accept the plain Go numeric kinds for the benefit of hand-built test doubles.
  • The only evaluation that performs I/O is a targeted boolean one. Everything else is served from the client’s in-memory cache; the initial sync, background refresh and SSE stream are handled by the *nexus.Client.
  • Provider metadata name is "Nexus".

Module path

Latest release: v0.16.1 (2026-08-30)

Reacting to a configuration change

The provider implements the OpenFeature EventHandler contract: when the Nexus client replaces its cache, the provider emits PROVIDER_CONFIGURATION_CHANGED naming the flag keys whose value moved, so a handler registered through the OpenFeature API is called.
The same change drops the provider’s per-user evaluation cache. That matters even when no snapshot value moved: a rollout percentage or a cohort rule can change without any flag’s static value changing, and a memoised targeted answer would otherwise be served until its own TTL expired. Close() releases the provider’s subscription on the client. It is optional - closing the client releases it too - and calling it twice is a no-op.

Construction errors

NewProvider(client, opts...) (*NexusProvider, error) is the constructor to prefer: it reports a nil client and an invalid option as an error. New(client, opts...) is the Must-style form and panics on the same conditions, the way regexp.MustCompile does.