rollfuse
← Back to blog

Feature Flags in Node.js: A Quickstart With js-sdk

js-sdk (the RollfuseClient at the center of the sdk-js/sdk-browser/sdk-react family) evaluates flags locally against a Configuration it fetches once and keeps warm with background polling. Like go-sdk on the Go side, evaluation never makes a network call: the request path reads a cached Configuration, and both SDKs are checked against the same golden bucketing vectors so a subject buckets identically no matter which one evaluated them.

Install and construct a client

npm install @rollfuse/sdk-js
import { RollfuseClient } from "@rollfuse/sdk-js";

const client = new RollfuseClient({
  credential: process.env.ROLLFUSE_CREDENTIAL!, // set before running
  baseUrl: process.env.ROLLFUSE_BASE_URL!, // e.g. https://api.rollfuse.com
});

await client.start();

The constructor never fetches on its own: start() is what begins polling GET /v1/config and returns a Promise that resolves once the first Configuration lands. A service that would rather not block startup on that call can call start() fire-and-forget instead, and let evaluate()'s fallback option carry evaluations until the first fetch completes.

Evaluate a flag

const result = client.evaluate(subjectKey, "checkout-redesign", {
  attributes: { plan: "growth" },
  fallback: false,
});

if (result.value === true) {
  // serve the new checkout
}

evaluate() is synchronous and deterministic: same subject, same flag, same Configuration version, same result, every time, with no request in flight while your code is waiting on it. If the Configuration hasn't loaded yet, or the platform is briefly unreachable and a fetch fails, evaluate() returns the fallback you supplied instead of throwing, so a flag evaluation is never the reason a request fails.

What happens on the backend being briefly unreachable

js-sdk keeps serving the last successfully fetched Configuration if a background refresh fails. It does not clear its cache on a failed poll, and it does not retry aggressively enough to add load during an incident. evaluate() stays available with whatever Configuration it last had, which is the platform-availability decoupling the whole local-evaluation design exists for: a rollfuse outage degrades to "flags stop changing," not "flags stop evaluating."

Exposure reporting

Every rule-matched evaluation is queued and reported to POST /v1/exposure-events asynchronously, batched by size or a flush interval, whichever comes first. This never adds latency to evaluate(). Call client.close() on shutdown (or before a serverless function's invocation ends) to flush anything still queued.

See the js-sdk repository for sdk-browser and sdk-react bindings, and examples-node-opentelemetry for a runnable service.