SDKs

@flagbearer/node

The Node.js SDK for Flagbearer. Requires Node.js 22 or later.

Install

npm install @flagbearer/node

Keys

Use a server key, which starts with fbs_. Server keys are secret: read them from the environment, such as FLAGBEARER_SERVER_KEY, and never put them in browser code or in the repository. Browsers use client keys, which start with fbc_, through @flagbearer/web.

Sync at startup

Create one client per process, when the app starts, and wait for it to sync before accepting requests:

import { init } from "@flagbearer/node";

export const flags = init({
  key: process.env.FLAGBEARER_SERVER_KEY!,
});

try {
  await flags.sync();
} catch (error) {
  console.error("Initial Flagbearer sync failed", error);
  // Keep starting: checks use their defaults, and the SDK retries in the background.
}

Check per request

Pass each request's user explicitly, and a default:

app.get("/search", (req, res) => {
  const user = { key: req.user.id, email: req.user.email };
  const advanced = flags.isEnabled("advanced-search", user, false);
  // …
});

The email is optional. Include it to turn flags on for testers by email. The default is used until the client has synced, and when the flag doesn't exist.

Typed flag keys

In TypeScript, the CLI can write a file listing the application's flags. Then a misspelled key is a type error, and editors autocomplete keys:

npx @flagbearer/cli generate types --app <app> --out src/flagbearer.d.ts
flags.isEnabled("new-checkout", user, false); // ok
flags.isEnabled("new-chekout", user, false); // type error: not a flag in this app

Commit the file, and run the command in its first line again after adding or removing a flag. Without the file, any string is a flag key.

Error reports

allFlags() returns every flag's current value, so error reports show exactly which flags were on. It doesn't count as checking them.

Sentry.setContext("flags", flags.allFlags(user));
// { "new-checkout": true, "dark-mode": false }

Pass the same user as the request's checks. Flags the client hasn't synced yet aren't included.

Shut down

Keep the client for the life of the process, not per request. Flush and close it on shutdown:

process.on("SIGTERM", async () => {
  try {
    await flags.flush();
  } finally {
    flags.close();
  }
});

Serverless functions should call flags.flush() at the end of each invocation.