Skip to content

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.

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.

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.

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.

Terminal window
npm install @feathq/web-sdk @feathq/openfeature-web @openfeature/web-sdk
import { 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.

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 reasonOpenFeature reason
TARGETING_MATCHTARGETING_MATCH
SPLITSPLIT
FALLTHROUGHDEFAULT
DEFAULTDEFAULT
DISABLEDDISABLED
ERRORERROR

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.