# @flagbearer/node

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

## Install

```sh
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`](/sdks/web).

## Sync at startup

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

```ts
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:

```ts
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](/sdks/cli) can write a file listing the application's
flags. Then a misspelled key is a type error, and editors autocomplete keys:

```sh
npx @flagbearer/cli generate types --app <app> --out src/flagbearer.d.ts
```

```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.

```ts
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:

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

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