Unleash OpenFeature Provider for Node.js
An OpenFeature provider backed by the official
Unleash Node.js SDK (unleash-client),
for server-side Node.js applications.
Adheres to OpenFeature specification v0.8.0
via @openfeature/server-sdk >=1.14.0
(the first release of the server SDK implementing spec v0.8.0). All required provider
behavior is implemented: typed flag resolution, evaluation context handling, lifecycle
(initialization/shutdown), and provider events. Of the spec's optional capabilities,
provider hooks and the tracking API (spec section 6) are not implemented — see
Out of scope.
The provider constructs and owns the Unleash client: it is created and started when the
provider is initialized, and destroyed (with a final metrics flush) when OpenFeature shuts
down. Flags are evaluated locally by the Unleash SDK against the translated evaluation
context, so Unleash usage metrics keep working as usual.
Installation
npm install @unleash/openfeature-node-provider @openfeature/server-sdk unleash-client
Usage
import { OpenFeature } from '@openfeature/server-sdk';
import { UnleashProvider } from '@unleash/openfeature-node-provider';
const provider = new UnleashProvider({
url: 'https://app.unleash-hosted.com/demo/api/',
appName: 'my-app',
customHeaders: { Authorization: '<your-api-token>' },
});
await OpenFeature.setProviderAndWait(provider);
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue('my-flag', false, { targetingKey: 'user-123' });
const variantText = await client.getStringValue('my-copy-experiment', 'default text', {
targetingKey: 'user-123',
sessionId: 'session-1',
region: 'EMEA',
});
The underlying Unleash client is available as an escape hatch via provider.unleashClient.
Concept mapping
Flag evaluation
getBooleanValue / getBooleanDetails | isEnabled() |
getStringValue / getStringDetails | variant payload of type string or csv |
getNumberValue / getNumberDetails | variant payload of type number |
getObjectValue / getObjectDetails | variant payload of type json (parsed) |
If the variant payload type does not match the requested type, the evaluation returns the
default value with errorCode: TYPE_MISMATCH. A flag that does not exist in Unleash returns
the default value with errorCode: FLAG_NOT_FOUND (note that this differs from the raw
Unleash SDK, which treats unknown flags as disabled). Disabled flags resolve variant
evaluations to the default value with reason DISABLED; enabled flags without an assigned
variant (or without a payload) resolve to the default value with reason DEFAULT.
The assigned variant name is reported in variant, and flagMetadata carries
featureEnabled and payloadType.
Evaluation context
targetingKey | userId (takes precedence over an explicit userId key) |
userId, sessionId, remoteAddress, environment, appName | same field |
currentTime (Date or ISO string) | currentTime |
| any other key | properties.<key> |
Strings and numbers pass into properties unchanged; booleans and dates are stringified.
Nested objects and arrays are dropped (with a debug log), since Unleash constraints cannot
evaluate them.
Stickiness
Unleash resolves default stickiness for gradual rollouts and variant assignment internally,
falling back through userId → sessionId → random. The provider does not replicate or
alter this chain — it only fills in the fields. targetingKey fills userId; if you want
session-based stickiness, set sessionId in the evaluation context. A missing
targetingKey is never an error: evaluation falls through Unleash's normal chain and ends
at random stickiness. Custom stickiness on a custom context field works via properties.
Events and lifecycle
| ready + synchronized | PROVIDER_READY |
| configuration changed | PROVIDER_CONFIGURATION_CHANGED |
| fetch error while cached flags are served | PROVIDER_STALE |
| error before any flag data is available | PROVIDER_ERROR |
| recovery after an error | PROVIDER_READY |
initialize() rejects on the first Unleash error instead of waiting forever, so
setProviderAndWait() cannot hang on a misconfigured connection. The Unleash client keeps
retrying in the background and the provider recovers (emitting PROVIDER_READY) once a
fetch succeeds.
Reasons
Unleash does not expose which strategy matched an evaluation, so reasons are best-effort:
TARGETING_MATCH for enabled flags, DISABLED for disabled ones, SPLIT for assigned
variants, DEFAULT when the default value is used, and ERROR alongside an error code.
Out of scope
The OpenFeature tracking API is not implemented. Unleash impression data and usage metrics
are unaffected — they are handled by the underlying SDK.
Development
npm install
npm test
npm run build
License
Apache-2.0