Guides

SDK Client Guide

Install and use the TypeScript SDK for bootstrapping and locally evaluating FlagForge feature flags

SDK Client Guide

The FlagForge SDK downloads flag definitions once, then evaluates feature flags in your Node.js process. After initialization, flag checks are synchronous and do not make a network request for each call.

The SDK uses a client key and an environment key to bootstrap from your self-hosted API. It evaluates the downloaded flags with the shared @flagforge/core engine, including targeting rules, segments, and rollouts.

Install the SDK

Install the package in the Node.js or TypeScript application that will evaluate flags:

bash
pnpm add @flagforge/sdk

The SDK uses the standard fetch implementation available in current Node.js runtimes. If your runtime does not provide fetch, pass a compatible implementation through the fetch option.

Note:

Use a client key for application evaluation. Do not put an administrative server key in application configuration that can be exposed to users or client-side code.

Initialize the client

Create one client for the API and environment your application uses, then initialize it during application startup.

1

Provide the API base URL, a client key belonging to the project, and the environment key whose flags should be evaluated.

1

Call and await client.init(). The SDK sends GET /v1/config?environment=<environment> with an Authorization: Bearer <client-key> header. The response supplies the environment's flags and segments for local evaluation.

1

After init() resolves, call a typed getter or variation helper with an optional evaluation context. Check client.ready when code needs to know whether initialization has completed.

typescript
import { FlagForgeClient } from '@flagforge/sdk';

const client = new FlagForgeClient({
  clientKey: process.env.FLAGFORGE_CLIENT_KEY!,
  baseUrl: process.env.FLAGFORGE_API_URL ?? 'http://localhost:4000',
  environment: process.env.FLAGFORGE_ENVIRONMENT ?? 'production',
});

await client.init();
console.log(client.ready); // true

const context = {
  key: user.id,
  attributes: { plan: user.plan, country: user.country },
};

if (client.isEnabled('new-checkout', context)) {
  renderNewCheckout();
}

The bootstrap request is the SDK's network operation. Once it succeeds, evaluation uses the in-memory definitions. If bootstrap returns a non-successful HTTP response, init() rejects with an error containing the response status.

Supply an evaluation context

An evaluation context identifies the subject and supplies attributes used by targeting rules and segments:

typescript
const context = {
  key: 'user-123',
  attributes: {
    plan: 'pro',
    country: 'US',
    beta: true,
    accountAgeDays: 42,
  },
};

const enabled = client.isEnabled('new-checkout', context);

key must be a stable string. Percentage rollouts use it as their default bucketing value, so keeping it stable keeps a subject in the same rollout bucket. Attributes may be strings, numbers, or booleans.

If you omit the context, the SDK evaluates with { key: "anonymous" }. Use an explicit context for user- or account-targeted flags.

Read typed flag values

Use the getter that matches the flag's configured type. Every typed getter takes a fallback value for unknown flags or incompatible values.

MethodReturnsFallback behavior
isEnabled(key, context?)booleanReturns false for an unknown flag.
getString(key, defaultValue, context?)stringReturns defaultValue for an unknown or non-string value.
getNumber(key, defaultValue, context?)numberReturns defaultValue for an unknown or non-number value.
getJson(key, defaultValue, context?)JSON valueReturns defaultValue for an unknown flag.
typescript
const showNewCheckout = client.isEnabled('new-checkout', context);
const theme = client.getString('checkout-theme', 'control', context);
const maxItems = client.getNumber('max-cart-items', 10, context);
const checkoutOptions = client.getJson(
  'checkout-options',
  { showCoupons: false },
  context,
);

isEnabled returns true only when the resolved value is true; use the other getters for remote configuration values.

Use variation helpers

Use variation when you want the resolved raw value and a fallback:

typescript
const layout = client.variation('checkout-layout', 'control', context);
const retryLimit = client.variation('retry-limit', 3, context);

For diagnostics, detailedVariation returns the complete evaluation result, including value and reason. It returns null when the flag key is not present in the bootstrapped configuration.

typescript
const result = client.detailedVariation('new-checkout', context);

if (result) {
  console.log({ value: result.value, reason: result.reason });
}

variation returns its fallback when the flag is unknown or evaluation produces an error. Prefer typed getters in application code so an unexpected flag type also falls back safely.

Refresh definitions

Polling is disabled by default. To refresh definitions yourself, call refresh():

typescript
await client.refresh();

refresh() replaces the in-memory flags and segments with the latest response and invokes registered change listeners.

Enable background polling with pollIntervalMs, in milliseconds:

typescript
const client = new FlagForgeClient({
  clientKey: process.env.FLAGFORGE_CLIENT_KEY!,
  baseUrl: 'https://flags.example.com',
  environment: 'production',
  pollIntervalMs: 30_000,
});

await client.init();

A value of 0, or omitting the option, disables polling. Polling starts after the initial bootstrap succeeds. Failed background refreshes are ignored by the polling loop, so the client continues using its last successfully loaded definitions.

Listen for flag changes

Register a listener with onChange. The returned function removes that listener:

typescript
const unsubscribe = client.onChange(() => {
  updateCheckoutTheme(
    client.getString('checkout-theme', 'control', context),
  );
});

await client.refresh();
unsubscribe();

Listeners run after a successful init() bootstrap or refresh(). They do not receive a payload; read current values from the client inside the callback.

Shut down the client

Call close() when the client is no longer needed. It stops background polling and releases registered listeners:

typescript
client.close();

Related documentation

How evaluation works

Understand targeting, segments, rollouts, and evaluation reasons.

Bootstrap flag config

Inspect the REST endpoint used by the SDK to load definitions.

Core evaluation engine

Reuse the pure TypeScript evaluator in a custom runtime.