Flags guides
03 · OpenFeature
Use the OpenFeature API.
Keep your code on the vendor-neutral OpenFeature server SDK and let Flags evaluate underneath.
1
Install and register the provider
terminal
npm install @openfeature/server-sdk @productcraft/flags @productcraft/flags-openfeatureThe provider takes the same options as FlagsClient (polling, cache, bootstrap, overrides) and evaluates locally, like the plain SDK.
flags.ts
import { OpenFeature } from "@openfeature/server-sdk";
import { ProductCraftFlagsProvider } from "@productcraft/flags-openfeature";
// Takes FlagsClient options (polling, cache, bootstrap, overrides …).
await OpenFeature.setProviderAndWait(
new ProductCraftFlagsProvider({ sdkKey: process.env.PRODUCTCRAFT_FLAGS_SDK_KEY }),
);
const client = OpenFeature.getClient();
const context = { targetingKey: "user-123", email: "ada@example.com", plan: "pro" };
const enabled = await client.getBooleanValue("new_checkout", false, context);
const banner = await client.getStringValue("banner_text", "Welcome", context);
const limits = await client.getObjectValue("limits", { max: 5 }, context);
const details = await client.getBooleanDetails("new_checkout", false, context);
console.log(enabled, banner, limits, details.reason, details.variant, details.flagMetadata);
await OpenFeature.close(); // closes the FlagsClient underneath2
How the context maps
| OpenFeature | Flags |
|---|---|
targetingKey | identifier (the attribute percentage splits hash) |
email, country | the top-level user fields |
other strings, numbers, booleans, Dates, string[] | custom attributes rules can target |
nested objects, mixed arrays | dropped (logged at debug level) |
object resolver | a json setting, parsed |
reason | STATIC, TARGETING_MATCH, SPLIT, DEFAULT, CACHED, STALE, ERROR |
variant | rule:<i>, rule:<i>/pct:<j>, pct:<j> or default |
flagMetadata | revision, plus rule_index / percentage_index |
errorCode | FLAG_NOT_FOUND, TYPE_MISMATCH, PARSE_ERROR, PROVIDER_NOT_READY; prerequisite errors are GENERAL |
3
Lifecycle and events
- Initialisation waits for the first download, at most
polling.maxInitWaitSeconds(5 by default). It fails only when there is no config at all: no download, no cache, no bootstrap. PROVIDER_CONFIGURATION_CHANGEDfires when a new revision is adopted, with the changed keys.PROVIDER_STALEwhen a download fails while an older config is served;PROVIDER_ERRORwhen the SDK key is unknown, revoked or expired (the held config is still served).- Evaluations never throw: on any failure you get your default with reason
ERROR.
4
In tests
checkout.test.ts
import { OpenFeature } from "@openfeature/server-sdk";
import { createTestClient } from "@productcraft/flags/testing";
import { ProductCraftFlagsProvider } from "@productcraft/flags-openfeature";
const client = createTestClient({ values: { new_checkout: true } });
await OpenFeature.setProviderAndWait(new ProductCraftFlagsProvider({ client }));
client.set("new_checkout", false); // emits PROVIDER_CONFIGURATION_CHANGED