Skip to content

NodeJS SDK

The @featureboard/node-sdk is a FeatureBoard SDK for NodeJS.

Prerequisites

Before using @featureboard/js-sdk you will need to have a valid environmentApiKey. To locate the Environment API Key, simply go to the “Product Settings” section and copy the key for your environment.

Installation

Terminal window
npm add --save @featureboard/node-sdk
# Or
yarn add @featureboard/node-sdk
# Or
pnpm add @featureboard/node-sdk

Setup

To integrate feature toggles in your Node.js project you need to create and configure the FeatureBoard service. The server client is created for a specific environment and the environment api key you can find by navigating to the “Product Settings” section.

import { createServerClient } from '@featureboard/node-sdk'
const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
})
// Wait for the server client to initialise
await serverClient.waitForInitialised()

Input Parameters

  • environmentApiKey- Specifies the environment api key for the environment.
  • updateStrategy- Configure preferred update strategy. The default strategy is polling at 30-second interval.
  • externalStateStore- Provides the option to configure external state store in cases where FeatureBoard is unavailable.

Return Properties

Returns a ServerClient object.

  • request() - Get a FeatureBoardClient based on an audience set.
  • initialised - Returns true once the FeatureBoard SDK has a valid set of feature values.
  • waitForInitialised() - Waits for the server client to be initialised. If initialisation fails an error is thrown.
  • updateFeatures() - Manually trigger the feature state store to update.
  • close() - Close the subscription to the FeatureBoard service.

Configuration Options

Choose Update Strategy

Our SDKs are designed to work with different update strategies. You can choose update strategy by configuring the updateStrategy input parameter. Featureboard NodeJS SDK supports following update strategies:

  • polling
  • manual updating
  • on request

Default update strategy is polling at 30-second interval. Live updates are being developed, if you are interested in this feature please contact us at support@featureboard.app.

Polling

To use polling update strategy you can configure updateStrategy to 'polling' and the server client will poll the FeatureBoard service at the default 30-second interval. To change the interval, you need to set intervalMs in PollingOption.

const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
// Set update strategy to polling at default 30-second interval
updateStrategy: 'polling',
})
// or
const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
// Set update strategy to polling at 5-second interval
updateStrategy: { kind: 'polling', options: { intervalMs: 5000 } },
})
Manual

If you prefer the application to have more direct control over features updates, you can configure 'updateStrategy' to 'manual'. To initiate the update process you utilise the updateFeature function.

const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
updateStrategy: 'manual',
})
// Wait for the server client to initialise
await serverClient.waitForInitialised()
// Triggers an update of the feature state store
await serverClient.updateFeatures()
On Request

This update strategy is useful for serverless applications where the VM gets paused between invocations, it will guarantee that the feature values are always up to date for the current invocation.

const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
// Set update strategy to on request with default max age cache of 30 seconds
updateStrategy: 'on-request',
})
// Wait for the server client to initialise
await serverClient.waitForInitialised()
// NOTE: request function must be awaited when using the on-request strategy
const requestClient = await serverClient.request(['admin', 'plan-large'])

By default, the on-request strategy has a max age cache of 30 seconds. If you wish to reduce cache time, you can achieve that by providing an OnRequestOptions configuration object. This configuration ensures that the SDK will only check if the feature values have changed after the max age has passed since the last update.

const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
// Set update strategy to on request with max age cache of 1 second
updateStrategy: { kind: 'on-request', options: { maxAgeMs: 1000 } },
})
// Wait for the server client to initialise
await serverClient.waitForInitialised()
// NOTE: request function must be awaited when using the on-request strategy
const requestClient = await serverClient.request(['admin', 'plan-large'])

Note: The request function must be awaited when using the on-request update strategy. If not awaited an error will be thrown.

External State Store

You can provide the server client with the last know set of feature values by implementing the ExternalStateStore interface. If FeatureBoard is unavailable during initialisation, the SDK will retrieve features from the external state store by calling all. To keep the external state store accurate, the SDK will call update with a copy of the internal state store each time a feature is changed.

import { ExternalStateStore } from '@featureboard/node-sdk'
import { FeatureConfiguration } from '@featureboard/contracts'
export class YourExternalStateStore implements ExternalStateStore {
private store: Record<string, FeatureConfiguration | undefined> = {}
async all(): Promise<Record<string, FeatureConfiguration | undefined>> {
// Return a stable copy of the feature values
return { ...this.store }
}
async update(store: Record<string, FeatureConfiguration | undefined>): PromiseLike<any> {
// Update the external state store with the provided feature values
this.store = { ...store }
return Promise.resolve()
}
}
import { createServerClient } from '@featureboard/node-sdk'
const myStateStore = new YourExternalStateStore()
const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
externalStateStore: myStateStore,
})
// Wait for the server client to initialise
await serverClient.waitForInitialised()

Note: The SDK will ignore any errors thrown in update.

Self Hosted Instance

By configuring the api input parameter you can connect to a shelf hosted instance of FeatureBoard.

const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
api: {
http: 'https://my-featureboard-endpoint'
ws: 'wss://my-websocket-featureboard-endpoint'
},
})

Wait For Initialised

Before you begin using the FeatureBoard server client, it is important to ensure that the server client has been initialised with feature values. You achieve this by awaiting the waitForInitialised function.

In the unlikely event of encountering a connectivity issue with FeatureBoard, the server client will make multiple retry attempts. If the retries fails, FeatureBoard will try to initiate by using the external state store if it has been defined. If all fail, waitForInitialised will throw an error. To handle this error, you can wrap the waitForInitialised function in a try-catch block. This way, you can handle any potential issues that might arise during the initialisation process.

try {
const serverClient = createServerClient({
environmentApiKey: 'my-environment-api-key',
})
// Wait for the server client to initialise
await serverClient.waitForInitialised()
} catch (err: any) {
// An error occurred during initialisation
throw err
}

Usage

To retrieve feature values, you will need to untilise the FeatureBoardClient, which is based on an audience set. This would normally happen at the beginning of an HTTP request within your Node.js application.

This setup is designed to ensure that FeatureBoard does not impact response times of your application. It allows the SDK to calculate the feature values for that user based on their audiences on the fly in memory.

// Get the FeatureBoard client for the current request
const client = serverClient.request(['audience-key-1', 'audience-key-2'])

Get Feature Value

The getFeatureValue function returns the feature value for a given feature. The default value is used as a fallback in cases where the feature is unavailable in the current environment.

// First get the FeatureBoard client for the current request
const client = serverClient.request(['audience-key-1', 'audience-key-2'])
// Then use the client in your application to get the current feature value.
// NOTE: You must specify a default value, this is used when the feature is unavailable in this environment
const featureValue = client.getFeatureValue('my-feature-key', defaultValue)

Universal JavaScript Applications

For universal JavaScript applications where you want to use the SDK on the server and client, the SDK returned from the request message is the same shape as the client from @featureboard/js-sdk, making FeatureBoard SDKs easy to use with frameworks like Next.js.

Note: When subscribeToFeatureValue is used in FeatureBoard Node SDK, it will only call back once. It will immediately call back with the current value but will not subscribe to the feature in the state store.

TypeScript support

See TypeScript support for more information.

Debugging

To enable debug logging, set the DEBUG environment variable to @featureboard/node-sdk,@featureboard/node-sdk:*.

Available scopes are:

  • @featureboard/node-sdk
  • @featureboard/node-sdk:http-client
  • @featureboard/node-sdk:server-connection
  • @featureboard/node-sdk:updates

Manual Client

The JavaScript SDK enables you to create a manual client to use the FeatureBoard SDK without talking to the service. This can be useful for unit testing, getting started with FeatureBoard, local development and also if you no longer need the service to remove your reliance on the service without having to remove the SDK.

For the NodeSDK you implement the function which takes an audience set, and returns the features.

import { createManualServerClient } from '@featureboard/node-sdk'
createManualServerClient((audiences) => ({
'seed-with-demo-data': audiences.includes('plan-demo'),
}))