OpenFeature
OpenFeature is a CNCF specification for a vendor-neutral feature flag API. feat ships a Provider for the OpenFeature web SDK and exports a Provider class from @feathq/js-sdk for the server SDK. If you write your code against OpenFeature, you can swap feat for any other OpenFeature-compatible vendor without changing application code.
Why OpenFeature
Section titled “Why OpenFeature”Two practical reasons:
- Vendor portability. Your application code calls
OpenFeature.getClient().getBooleanValue(...). Swapping the Provider is a one-line change. The rest of your app does not care. - Standard surface. Engineers familiar with OpenFeature do not have to learn a new client API.
Spec reference: openfeature.dev/specification.
Server-side: @feathq/js-sdk
Section titled “Server-side: @feathq/js-sdk”The FeatProvider class is bundled with @feathq/js-sdk. No extra install required.
import { OpenFeature } from "@openfeature/server-sdk";import { FeatClient, FeatProvider } from "@feathq/js-sdk";
const featClient = new FeatClient({ apiKey: process.env.FEAT_SERVER_KEY!, dataPlaneUrl: "https://data.feat.so",});
await OpenFeature.setProviderAndWait(new FeatProvider(featClient));
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue("checkout-v2", false, { targetingKey: "user-123", plan: "pro",});See Node.js SDK for everything else the client supports.
Web: @feathq/openfeature-web
Section titled “Web: @feathq/openfeature-web”The web Provider is a separate package because the OpenFeature web spec separates “evaluation context lives on the provider” from “context is passed per call.” The web Provider routes context through OpenFeature.setContext.
npm install @feathq/web-sdk @feathq/openfeature-web @openfeature/web-sdkimport { OpenFeature } from "@openfeature/web-sdk";import { FeatWebClient } from "@feathq/web-sdk";import { FeatWebProvider } from "@feathq/openfeature-web";
const featClient = new FeatWebClient({ apiKey: "feat_cs_…", dataPlaneUrl: "https://data.feat.so",});
await OpenFeature.setProviderAndWait(new FeatWebProvider(featClient));await OpenFeature.setContext({ targetingKey: "user-123" });
const client = OpenFeature.getClient();const enabled = client.getBooleanValue("checkout-v2", false); // sync@feathq/web-sdk and @openfeature/web-sdk are peer dependencies. Use OpenFeature.setContext (not the per-call context) for the web Provider; it routes through to client.setContext on the underlying feat client.
Type coercion and reasons
Section titled “Type coercion and reasons”The Provider returns the supplied default value with TYPE_MISMATCH if you ask a boolean flag for a string, etc. The reason field carries through TARGETING_MATCH, SPLIT, FALLTHROUGH, DEFAULT, DISABLED, and ERROR; see Evaluation order for what each means.
OpenFeature’s reason vocabulary is close but not identical to feat’s. The Provider maps:
| feat reason | OpenFeature reason |
|---|---|
TARGETING_MATCH | TARGETING_MATCH |
SPLIT | SPLIT |
FALLTHROUGH | DEFAULT |
DEFAULT | DEFAULT |
DISABLED | DISABLED |
ERROR | ERROR |
Other languages
Section titled “Other languages”The Go, Python, and Ruby SDKs expose the feat-native API documented in their per-language pages. A Provider for each is planned; use the native API in the meantime.