Skip to main content
The Foff TypeScript SDK integrates feature flag resolution into any Node.js application. It polls the Foff API in the background, caches configs in memory, and lets you resolve the right flag value for any hierarchy with a single synchronous call. The package ships with full TypeScript types.

Requirements

Node.js 18 or later.

Installation

Quick start

Store your API key in an environment variable such as FOFF_API_KEY and read it with process.env.FOFF_API_KEY. Never hard-code it in source files.

Configuration

Create a Config instance with the fields below and pass it to Client.newClient.

Validation

Client.newClient validates the config before creating the client. It throws an error if APIKey, BaseURL, or Scope is missing or empty.

Polling interval normalization

The polling interval is clamped to safe bounds automatically before the client starts.
If you set PollingInterval below 10 seconds, the SDK raises it to 10. If you set it above 3600 seconds (1 hour), the SDK lowers it to 3600. Set it to 0 to disable polling entirely.

Creating a client

Client.newClient performs the following steps in order:
1

Validate the config

Checks that APIKey, BaseURL, and Scope are non-empty. Throws if any required field is missing.
2

Normalize the polling interval

Clamps PollingInterval to the range 10–3600 seconds (unless it is 0).
3

Fetch all configs (blocking)

Makes an HTTP GET request to {BaseURL}/api/v1/scopes/{scope}/configs and populates the in-memory cache.
4

Start background polling

If PollingInterval > 0, starts a timer that re-fetches configs on the configured interval.
The initial fetch is blocking. If the Foff API is unreachable or returns an error at startup, newClient throws that error immediately. Handle it at startup so your process fails fast rather than serving stale or empty configs.

Resolving feature configs

getFeatureConfig(featureName, orderedHierarchy)

Returns the config value for a feature, resolved against a hierarchy. The call is synchronous and reads from the in-memory cache — no network request is made.

Hierarchy resolution algorithm

The SDK resolves from most-specific to least-specific:
  1. It checks the full combination first — org-1 + team-a + user-123.
  2. It then tries shorter prefixes — org-1 + team-a, then org-1.
  3. If no override matches, it returns the feature’s "default" value.
  4. If the feature does not exist at all, it returns null.
This means you can define overrides at any level of your hierarchy — organisation, team, user, environment, region, service — and the SDK finds the most specific match automatically.

Polling

When PollingInterval is greater than 0, the SDK polls GET {BaseURL}/api/v1/scopes/{scope}/configs in the background and replaces the in-memory cache on each successful response.
  • Polling errors are silently ignored. The SDK continues serving the last successfully fetched config.
  • Calling client.close() stops the background timer and releases all resources.

Client lifecycle

For short-lived scripts, use a try/finally block to guarantee the client is closed:
For long-lived processes such as an Express server, create the client once at startup and close it on process exit: