JavaScript / TypeScript
The official ShipSilently SDK for Node.js, Bun, Deno, Cloudflare Workers, and the browser. Ships as ESM and CJS with full TypeScript types.
Install
npm install @shipsilently/nodebun add @shipsilently/nodeyarn add @shipsilently/nodepnpm add @shipsilently/nodeInitialize the client
Create one client at app startup and reuse it for the lifetime of the process.
import { ShipSilentlyClient } from '@shipsilently/node';
export const flags = new ShipSilentlyClient({
apiKey: process.env.SHIPSILENTLY_KEY!,
// apiUrl defaults to https://shipsilently-cf.workers.dev, override to pin a region or self-host
}); const { ShipSilentlyClient } = require('@shipsilently/node');
const flags = new ShipSilentlyClient({
apiKey: process.env.SHIPSILENTLY_KEY,
});
module.exports = { flags }; Configuration options
apiKey: required. Server keys start withsk_live_, client keys withpk_live_.apiUrl: override the API endpoint. Defaults tohttps://shipsilently-cf.workers.dev.fetch: inject a customfetchimplementation (useful in test environments).
Evaluate a single flag
Use evaluate() for a one-off async lookup. The third argument is
the default value returned on network errors or unknown flags, types are
inferred from it.
import { flags } from './flags';
const useNewFlow = await flags.evaluate('new-checkout-v2', {
userId: user.id,
plan: user.plan,
country: user.country,
}, false);
const heroVariant = await flags.evaluate('hero-variant', {
userId: user.id,
}, 'control'); // returns 'control' | 'a' | 'b'Evaluate all flags at once
evaluateAll() returns every flag in one round trip, ideal at
request boundaries. Pair it with get() for synchronous lookups
afterwards.
await flags.evaluateAll({ userId: user.id, plan: user.plan });
// Synchronous reads, <1ms, hits the in-memory cache
const showBanner = flags.get('promo-banner', false);
const tier = flags.get('pricing-tier', 'standard');Stream flag updates
For long-running services, subscribe to a Server-Sent Events stream so flag changes propagate without polling. The client auto-reconnects with exponential backoff.
const stop = flags.stream(
{ userId: 'system' },
(updated) => {
console.log('flags refreshed:', Object.keys(updated));
},
);
// later, on shutdown
stop();Types
The SDK ships with full TypeScript types. The most common shapes:
export type FlagValue = boolean | string | number | Record<string, unknown>;
export interface UserContext {
userId?: string;
email?: string;
country?: string;
plan?: string;
[key: string]: string | number | boolean | undefined;
}
export interface EvaluationResult {
flagKey: string;
value: FlagValue;
reason: 'default' | 'rule_match' | 'rollout' | 'flag_disabled' | 'flag_not_found';
ruleId?: string;
}Framework integrations
The SDK has zero framework dependencies and runs anywhere standard fetch is available:
- Next.js: initialize once in a server-only module; call
evaluateAll()in route handlers or RSCs. - Cloudflare Workers: instantiate per-request with the
env.SHIPSILENTLY_KEYbinding. - Bun / Deno: works natively, no polyfills needed.
- Browser: use a public client key (
pk_live_…); the client never exposes secrets.
sk_live_…) to the
browser. Server keys can edit flag definitions; client keys can only evaluate.