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:
pnpm add @flagforge/sdkThe 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.
Provide the API base URL, a client key belonging to the project, and the environment key whose flags should be evaluated.
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.
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.
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:
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.
| Method | Returns | Fallback behavior |
|---|---|---|
isEnabled(key, context?) | boolean | Returns false for an unknown flag. |
getString(key, defaultValue, context?) | string | Returns defaultValue for an unknown or non-string value. |
getNumber(key, defaultValue, context?) | number | Returns defaultValue for an unknown or non-number value. |
getJson(key, defaultValue, context?) | JSON value | Returns defaultValue for an unknown flag. |
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:
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.
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():
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:
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:
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:
client.close();Related documentation
Understand targeting, segments, rollouts, and evaluation reasons.
Inspect the REST endpoint used by the SDK to load definitions.
Reuse the pure TypeScript evaluator in a custom runtime.