Node.js SDK
Server-side SDK for Node.js applications. Uses native http/https modules (no fetch dependency). For browser applications, see the JavaScript SDK.
Package: @toggletown/sdk-node
Installation
npm install @toggletown/sdk-node
Quick Start
import { ToggleTownClient } from '@toggletown/sdk-node';
const client = new ToggleTownClient('tt_live_your_api_key');
await client.initialize();
// Evaluate a flag
const enabled = client.getBooleanFlag('new-feature', false, {
userId: 'user-123',
plan: 'pro',
});
// Clean up on shutdown
process.on('SIGTERM', () => client.close());
Configuration
const client = new ToggleTownClient('tt_live_your_api_key', {
apiUrl: 'https://api.toggletown.com', // API endpoint (default)
pollingInterval: 30000, // Milliseconds between refreshes (default: 30000)
onError: (error) => { // Error callback for background polling
logger.error('Flag fetch error:', error);
},
});
| Option | Type | Default | Description |
|---|---|---|---|
apiUrl | string | https://api.toggletown.com | API endpoint URL |
pollingInterval | number | 30000 | Polling interval in ms |
onError | (error: Error) => void | — | Error callback for background fetch failures |
Flag Types
Boolean
const enabled = client.getBooleanFlag('feature-enabled', false, context);
String
const variant = client.getStringFlag('experiment-variant', 'control', context);
Number
const maxItems = client.getNumberFlag('max-items', 10, context);
JSON
const config = client.getJSONFlag('feature-config', { enabled: false }, context);
User Context
Pass user attributes for targeting and rollouts:
const context = {
userId: 'user-123',
email: '[email protected]',
plan: 'enterprise',
country: 'US',
};
const enabled = client.getBooleanFlag('premium-feature', false, context);
Express Integration
import express from 'express';
import { ToggleTownClient } from '@toggletown/sdk-node';
const app = express();
const flags = new ToggleTownClient('tt_live_xxx');
await flags.initialize();
// Middleware to build flag context from request
app.use((req, res, next) => {
req.flagContext = {
userId: req.user?.id,
plan: req.user?.plan || 'free',
country: req.headers['x-country'],
};
next();
});
app.get('/api/checkout', (req, res) => {
const newCheckout = flags.getBooleanFlag('new-checkout', false, req.flagContext);
if (newCheckout) {
return res.json({ flow: 'new' });
}
res.json({ flow: 'legacy' });
});
// Graceful shutdown
process.on('SIGTERM', () => {
flags.close();
process.exit(0);
});
app.listen(3000);
Fastify Integration
import Fastify from 'fastify';
import { ToggleTownClient } from '@toggletown/sdk-node';
const fastify = Fastify();
const flags = new ToggleTownClient('tt_live_xxx');
await flags.initialize();
fastify.decorate('flags', flags);
fastify.addHook('onRequest', (req, reply, done) => {
req.flagContext = { userId: req.user?.id };
done();
});
fastify.get('/api/feature', (req, reply) => {
const enabled = fastify.flags.getBooleanFlag('feature', false, req.flagContext);
reply.send({ enabled });
});
// Cleanup on close
fastify.addHook('onClose', () => flags.close());
Error Handling
Initialization errors are thrown — catch them to handle startup failures:
try {
await client.initialize();
} catch (error) {
console.error('Failed to initialize flags:', error);
// Continue with defaults or exit
}
Background polling errors are handled silently (logged to console) unless you provide an onError callback:
const client = new ToggleTownClient('tt_live_xxx', {
onError: (error) => {
logger.error('ToggleTown polling error:', error);
},
});
Thread Safety
The Node.js SDK is safe to use across async operations. A single client instance can be shared across your entire application — flag data is managed internally with no race conditions.
Debugging
const allFlags = client.getAllFlags();
console.log(allFlags);
console.log('Initialized:', client.isInitialized());
TypeScript
The SDK exports all types:
import { ToggleTownClient, ToggleTownConfig } from '@toggletown/sdk-node';
import type { EvaluationContext, FlagConfig } from '@toggletown/types';