Skip to content

Node.js SDK

@feathq/js-sdk is the server-side SDK for Node.js, Bun, and Deno. It fetches a per-environment datafile and evaluates flags locally.

Terminal window
npm install @feathq/js-sdk
# or
yarn add @feathq/js-sdk

Node.js 18 or newer (uses built-in fetch). Bun and Deno also work.

For browser code use @feathq/web-sdk.

import { FeatClient } from "@feathq/js-sdk";
const client = new FeatClient({
apiKey: process.env.FEAT_SERVER_KEY!, // feat_sdk_…
dataPlaneUrl: "https://data.feat.so",
});
await client.ready();
const result = await client.evaluate("checkout-v2", false, {
targetingKey: "user-123",
user: { plan: "pro", email: "alice@example.com" },
});
if (result.value) {
// …
}

Use a server API key (feat_sdk_…).

const enabled = await client.getBooleanValue(key, defaultValue, context);
const variant = await client.getStringValue(key, defaultValue, context);
const limit = await client.getNumberValue(key, defaultValue, context);
const config = await client.getObjectValue(key, defaultValue, context);
const detailed = await client.evaluate(key, defaultValue, context);
// detailed.value, detailed.variationId, detailed.reason, detailed.errorMessage

The shape of context is documented in Contexts.

reason is one of TARGETING_MATCH, SPLIT, FALLTHROUGH, DEFAULT, DISABLED, or ERROR. See Evaluation order for what each one means.

new FeatClient({
apiKey: process.env.FEAT_SERVER_KEY!,
dataPlaneUrl: "https://data.feat.so",
pollInterval: 30_000, // ms; default 30000, minimum 5000
bootstrap: serializedDatafile, // optional: skip the initial fetch
});

dataPlaneUrl must be https:// in production. Plaintext is rejected except for http://localhost during tests.

  • client.ready() resolves once the first datafile is loaded. Call evaluations only after.
  • The SDK polls in the background. New datafiles replace the in-memory copy atomically.
  • The SDK keeps a socket open for nothing; it is pure HTTP polling.
  • Call await client.close() on shutdown to stop the poller and drain in-flight requests.
import { OpenFeature } from "@openfeature/server-sdk";
import { FeatClient, FeatProvider } from "@feathq/js-sdk";
const featClient = new FeatClient({ apiKey, dataPlaneUrl });
await OpenFeature.setProviderAndWait(new FeatProvider(featClient));
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue("checkout-v2", false, {
targetingKey: "user-123",
});

See OpenFeature for more on the standard.