Skip to content

Server SDK

StatsKitServerClient runs on the server (Node, Bun, Deno, Cloudflare Workers, and other edge runtimes). It fetches the full compiled config once and evaluates every flag locally with the bundled engine, identical bucketing to the platform, no network per call, and full access to rules and segments.

Terminal window
npm install @statskit/sdk

Import from the /server entry point.

flags.ts
import { StatsKitServerClient } from "@statskit/sdk/server";
export const statskit = await new StatsKitServerClient({
serverKey: process.env.VERSUCH_SERVER_KEY!, // ssk_live_… or vsk_live_…
}).init();

The client fetches the full payload on init() and holds it in memory. On Node 18 and earlier, pass a fetch implementation via the fetch option.

Because the server holds the full config and evaluates locally, you pass the context per call. That’s what you want when one process serves many different users.

The context is { key, attributes }: key is the stable bucketing unit; attributes drive the targeting rules.

const ctx = { key: user.id, attributes: { plan: user.plan, country: user.country } };
const showBeta = statskit.boolVariation("beta-dashboard", ctx, false);

Evaluation never throws, a missing flag or an outage returns the default you passed.

allFlags(ctx) resolves every flag for a context in one pass, handy for a settings screen or for server-side rendering a bootstrap payload.

const flags = statskit.allFlags(ctx);

The server client detects publishes and hot-swaps the payload without a restart.

  • Polling (default): it polls the cheap GET /v1/config/version and only re-fetches the full config when the version changes. Server default is every 30s; set pollIntervalMs (0 disables).
  • Streaming: set stream: true to subscribe to the SSE change stream at /v1/config/stream for near-instant updates.
new StatsKitServerClient({ serverKey, stream: true }); // SSE
new StatsKitServerClient({ serverKey, pollIntervalMs: 10000 }); // faster poll

Evaluate on the server, inline the payload, and hand it to the browser client as bootstrap so the first paint matches the server with no network wait or flicker:

// server
const client = await new StatsKitServerClient({ serverKey }).init();
const flags = client.allFlags(ctx); // embed in HTML as window.__VERSUCH__
// browser
new StatsKitClient({ clientKey, bootstrap: window.__VERSUCH__ });

Emit custom-metric events from any backend with track(): the server-side companion to the tracker’s statskit.track():

// value is in MINOR units (cents); feeds "sum" / "mean" metrics
await statskit.track("user_123", "checkout", { value: 4999, currency: "usd" });
// conversion / count metrics need no value
await statskit.track("user_123", "support_ticket");

Persist the payload anywhere by passing a CacheAdapter (memory is built in; a file cache ships under @statskit/sdk/node):

import type { CacheAdapter } from "@statskit/sdk";
const redisCache: CacheAdapter = {
get: (k) => redis.get(k),
set: (k, v) => redis.set(k, v),
};
new StatsKitServerClient({ serverKey, cache: redisCache });

For the full options table and error handling, see the SDK overview.