Skip to content

JavaScript / TypeScript

The @edgeflags/sdk package provides a type-safe, real-time interface for reading feature flags and configs from any JavaScript runtime (browsers, Node.js, Deno, Bun, edge workers).

SDKs are also available for React and Python.

The SDK uses the bulk evaluation endpoint under the hood — flags and configs are fetched in a single request and cached locally for synchronous reads.

Installation

Terminal window
npm install @edgeflags/sdk

Quick start

import { EdgeFlags } from '@edgeflags/sdk';
const ef = new EdgeFlags({
token: 'ff_production_abc123',
baseUrl: 'https://edgeflags.net',
context: {
user_id: 'u_42',
plan: 'premium',
custom: { country: 'US' },
},
});
await ef.init();
const darkMode = ef.flag('dark_mode', false);
const limits = ef.config('api_limits', { requests_per_minute: 100 });

After init() resolves, all reads are synchronous from the local cache. The SDK polls for updates in the background.

Configuration

Pass these options to the EdgeFlags constructor:

OptionTypeDefaultDescription
tokenstringrequiredBearer token for authentication
baseUrlstringrequiredEdgeFlags API URL
contextEvaluationContextundefinedUser context for targeting evaluation
pollingIntervalnumber60000Background poll interval in milliseconds
bootstrapobjectundefinedInitial flag/config values for instant reads before init()
debugbooleanfalseLog SDK activity to the console

Evaluation context

The context object is sent with every evaluation request and drives targeting rules:

interface EvaluationContext {
user_id?: string;
email?: string;
phone?: string;
plan?: string;
segments?: string[];
environment?: string;
custom: Record<string, unknown>;
}

Reading flags

Use flag() to read a flag value. Pass a default as the second argument — its type narrows the return type.

// Returns boolean | string | number | object | undefined
const raw = ef.flag('dark_mode');
// Returns boolean (default provides type + fallback)
const darkMode = ef.flag('dark_mode', false);
// String flags
const banner = ef.flag('banner_text', '');
// Number flags
const limit = ef.flag('request_limit', 1000);
// JSON flags
const theme = ef.flag('theme_override', { primary: '#000' });

Use allFlags() to get every cached flag as a Record<string, FlagValue>.

Reading configs

Use config() the same way. The generic parameter provides type safety:

const providers = ef.config<PaymentConfig>('payment_providers', {
stripe_enabled: true,
paypal_enabled: false,
});
const all = ef.allConfigs();

Identifying users

Call identify() to update the evaluation context and immediately refresh all values:

await ef.identify({
user_id: 'u_99',
email: 'jane@example.com',
plan: 'enterprise',
custom: { beta_enrolled: true },
});
// Flags and configs now reflect the new user

Events

The SDK emits three events:

EventPayloadWhen
readyundefinedinit() completes successfully
changeChangeEventFlag or config values change after a poll
errorErrorNetwork or API error during polling
// Subscribe — returns an unsubscribe function
const off = ef.on('change', (event) => {
for (const { key, previous, current } of event.flags) {
console.log(`Flag ${key}: ${previous}${current}`);
}
});
ef.on('error', (err) => {
console.error('EdgeFlags polling error:', err);
});
// Unsubscribe
off();

Bootstrap and offline fallback

Provide bootstrap values so flags are available immediately, before the first network request:

const ef = new EdgeFlags({
token: 'ff_production_abc123',
baseUrl: 'https://edgeflags.net',
bootstrap: {
flags: { dark_mode: false, new_checkout: true },
configs: { api_limits: { requests_per_minute: 500 } },
},
});
// Available immediately — no await needed
const darkMode = ef.flag('dark_mode', false);
// init() will replace bootstrap values with live data
await ef.init();

Streaming mode

By default the SDK polls for updates on a fixed interval. When the EdgeFlags server has WebSocket support configured, you can switch to streaming mode for sub-50ms push updates instead:

const ef = new EdgeFlags({
token: 'ff_production_abc123',
baseUrl: 'https://edgeflags.net',
context: {
user_id: 'u_42',
custom: {},
},
streaming: true,
});
await ef.init();

With streaming: true, the SDK opens a WebSocket to /stream/flags, subscribes with the current context, and applies diffs as they arrive. The change event fires on each diff.

See the Real-time Streaming guide for full WebSocket protocol details.

Testing

Use createMockClient() to create a client that returns static values without making network requests:

import { createMockClient } from '@edgeflags/sdk';
const mock = createMockClient({
flags: { dark_mode: true, new_checkout: false },
configs: { api_limits: { requests_per_minute: 9999 } },
});
// Works like a real client
mock.flag('dark_mode', false); // true
mock.config('api_limits'); // { requests_per_minute: 9999 }

Cleanup

Call destroy() to stop polling and release resources:

ef.destroy();

Next steps

  • React SDK — hooks and context provider for React apps
  • Python SDK — async and sync clients for Python 3.10+