Node.js SDK
The @flagbridge/sdk-node package provides feature flag evaluation for Node.js and server-side TypeScript.
Installation
npm install @flagbridge/sdk-nodepnpm add @flagbridge/sdk-nodeyarn add @flagbridge/sdk-nodeRequirements: Node.js 18+ · TypeScript 5+ (optional)
Quick start
import { FlagBridgeClient } from '@flagbridge/sdk-node';
const client = new FlagBridgeClient({
apiKey: process.env.FLAGBRIDGE_API_KEY!,
// baseUrl defaults to https://api.flagbridge.io
});
// Boolean flag
const enabled = await client.isEnabled('new-checkout-flow', {
userId: 'user-123',
plan: 'pro',
});
// Multi-variant flag
const variant = await client.getVariant('checkout-button-color', {
userId: 'user-123',
});
// variant.value → "green" | "blue" | "red"
// variant.enabled → trueConfiguration
const client = new FlagBridgeClient({
// Required
apiKey: 'fb_live_...',
// Optional
baseUrl: 'https://api.flagbridge.io', // or your self-hosted URL
environment: 'production', // override environment
timeout: 5000, // request timeout in ms (default: 5000)
cache: {
ttl: 30_000, // in-memory cache TTL in ms (default: 30s)
maxSize: 1000, // max cached entries
},
onError: (err) => { // custom error handler
console.error('[FlagBridge]', err);
},
});INFO
By default, evaluation errors return false (flag disabled) so flag evaluation failures never break your application.
API
isEnabled(flagKey, context?)
Evaluates a boolean flag. Returns true if the flag is enabled for the given context.
const enabled = await client.isEnabled('my-flag', {
userId: 'user-123',
country: 'BR',
plan: 'pro',
});
// → true | falsegetVariant(flagKey, context?)
Evaluates a multi-variant flag and returns the variant result.
const result = await client.getVariant('button-color', {
userId: 'user-123',
});
result.value; // "green" — the variant value
result.enabled; // true
result.reason; // "TARGETING_RULE_MATCH" | "PERCENTAGE_ROLLOUT" | ...evaluate(flagKey, context?)
Low-level evaluation — returns the full result object.
const result = await client.evaluate('my-flag', { userId: 'user-123' });
result.flagKey; // "my-flag"
result.enabled; // true
result.variant; // null (or string for multi-variant flags)
result.reason; // "TARGETING_RULE_MATCH"
result.ruleId; // "rule_abc123"evaluateBatch(flags, context?)
Evaluate multiple flags in a single request.
const results = await client.evaluateBatch(
['new-checkout', 'dark-mode', 'sidebar-v2'],
{ userId: 'user-123' }
);
results['new-checkout'].enabled; // true
results['dark-mode'].enabled; // falseclose()
Flush pending requests and close the client. Call when shutting down.
await client.close();Caching
The SDK caches evaluation results in memory to avoid latency on every request. The cache is keyed by (flagKey, context hash).
const client = new FlagBridgeClient({
apiKey: '...',
cache: {
ttl: 60_000, // cache for 60 seconds
maxSize: 500, // LRU eviction when this limit is reached
},
});To disable caching (useful in testing):
const client = new FlagBridgeClient({
apiKey: '...',
cache: false,
});Testing helpers CE
The SDK ships with a TestingClient for use in your test suite. It uses the FlagBridge Testing API to create isolated sessions with per-flag overrides.
import { createTestingClient } from '@flagbridge/sdk-node/testing';
// In your test setup
const testClient = createTestingClient({
apiKey: process.env.FLAGBRIDGE_TEST_API_KEY!,
baseUrl: 'http://localhost:8080',
});
// Before each test
const session = await testClient.createSession();
// Override specific flags for this session
await session.override('new-checkout-flow', true);
await session.override('checkout-button-color', 'green');
// Run your test with the session token
// Pass the session token in your HTTP requests:
// X-FlagBridge-Session: <session.token>
// After each test
await session.destroy();See the E2E testing guide for full integration examples with Playwright and Vitest.
Framework integrations
Express / Fastify
import { flagBridgeMiddleware } from '@flagbridge/sdk-node/middleware';
// Express
app.use(flagBridgeMiddleware({
client,
contextFromRequest: (req) => ({
userId: req.user?.id,
plan: req.user?.plan,
}),
}));
// Now req.flags is available in your handlers
app.get('/checkout', async (req, res) => {
if (req.flags.isEnabled('new-checkout-flow')) {
return res.render('checkout-v2');
}
return res.render('checkout');
});Next.js (App Router)
// lib/flags.ts
import { FlagBridgeClient } from '@flagbridge/sdk-node';
export const flagbridge = new FlagBridgeClient({
apiKey: process.env.FLAGBRIDGE_API_KEY!,
});
// app/checkout/page.tsx
import { flagbridge } from '@/lib/flags';
import { cookies } from 'next/headers';
export default async function CheckoutPage() {
const userId = (await cookies()).get('user_id')?.value;
const newCheckout = await flagbridge.isEnabled('new-checkout-flow', {
userId,
});
if (newCheckout) {
return <NewCheckout />;
}
return <OldCheckout />;
}TypeScript
All methods are fully typed. You can declare your flag keys for autocomplete and type safety:
import { FlagBridgeClient } from '@flagbridge/sdk-node';
// Declare your flag keys
type FlagKey =
| 'new-checkout-flow'
| 'checkout-button-color'
| 'dark-mode';
const client = new FlagBridgeClient<FlagKey>({ apiKey: '...' });
// Now flagKey is typed
client.isEnabled('new-checkout-flow', { userId: 'user-123' }); // ✓
client.isEnabled('typo-flag', { userId: 'user-123' }); // ✗ TypeScript errorError handling
By default, evaluation failures silently return false. Override with onError:
const client = new FlagBridgeClient({
apiKey: '...',
onError: (error) => {
// Log to your error tracking
Sentry.captureException(error);
},
});For explicit error handling, use evaluate() with try/catch:
try {
const result = await client.evaluate('my-flag', { userId: 'user-123' });
} catch (err) {
// Handle error explicitly
}Changelog
See the SDK Node.js releases on GitHub.
