Node.js (client-side) SDK 3.x to 4.0 migration guide
Node.js (client-side) SDK 3.x to 4.0 migration guide
This topic explains the changes in the Node.js SDK 4.0 release and how to adapt code that uses a 3.x version of the Node.js SDK to use version 4.0 or later.
Version 4.0 includes several breaking changes.
Before you migrate to version 4.0, update to the latest 3.x version. Some of the changes that are mandatory in 4.0 were originally added in a 3.x version and made optional.
Supported Node.js versions for the 4.0 SDK
The minimum Node.js version for LaunchDarkly 4.0 SDK is 18.
LaunchDarkly no longer supports earlier Node.js versions, as stated in the End of Life policy.
Version 4.0 uses the native fetch and crypto.randomUUID internally so the SDK no longer depends on node-fetch or polyfills.
Package rename
The package name changed from launchdarkly-node-client-sdk to @launchdarkly/node-client-sdk.
First uninstall the v3.x package, then install the v4.0 package:
Update imports
Update any imports:
References
Update the following references:
- New signature:
createClient(envKey, initialContext, options): the initial context is required as the second argument. - Must call
start(): The client is no longer ready whencreateClientreturns. AftercreateClient(), the app must callclient.start()(optionally withLDStartOptions:timeout,bootstrap,identifyOptions). The promise returned bystart()resolves when the first identify completes (or times out, or fails). - No
identify()beforestart(): Callingidentify()beforestart()is an error (logged and rejected). Useidentify()only afterstart()has been called, for subsequent context changes.
Client initialization
In v4.0 of the SDK, client initialization has changed in the following ways:
- The
initializemethod was removed. - Initialization is now split into two parts:
createClientandstart. LDOptions, which was formerly passed into theinitialize()function, is now split into two types:LDStartOptionsandLDOptions. To learn more, read Changes to LDOptions.
This two-step process ensures that you can register all event listeners and perform any necessary setup before the client begins connecting to LaunchDarkly. This eliminates race conditions where events might be missed if listeners were registered after the client had already started initializing.
Here is the new client initialization method:
Client initialization flow
In v4.0 of the SDK, client initialization flow has changed in the following ways:
- In v4.0 the
waitForInitialization()method returns a result object instead of rejecting promises. The v3.xwaitUntilReady()method has been removed. waitForInitialization()now always resolves, never rejects, and returns a result object with astatusfield.timeoutis now specified as an option object,{ timeout: 5 }, instead of a direct parameter.- The result object lets you handle all cases, including success, failure, and timeout, without try/catch.
Here is the new client initialization flow:
Changes to LDOptions
In v4.0 of the SDK, LDOptions has changed in the following ways:
- The
bootstrapoption moved fromLDOptionstoLDStartOptionsandidentify. Bootstrapping data is now part of the initialization of a client instance.identifyis a key part of the client initialization process required to associate the instance with an initial context. - The SDK now defaults to using local storage-based caching. Previously, to enable local storage caching, you needed to set this as a special value for the
bootstrapproperty. - Version 3.x of the SDK used the
streamUrl,baseUrl, andeventsUrlproperties to specify the base URIs for alternative service endpoints. Version 4.0 of the SDK uses thestreamUri,baseUri, andeventsUriproperties to specify the base URIs for alternative service endpoints.
To learn more, read the following SDK documentation:
Identify flow
Version 4.0 identify() returns a promise that always resolves to an LDIdentifyResult object. It does not throw. Instead, success or failure is indicated by the resolved value.
Here are the return type and statuses:
- Return type:
Promise<LDIdentifyResult> - Result statuses:
{ status: 'completed' }: identification succeeded{ status: 'error', error: Error }: Identification failed.{ status: 'timeout', timeout: number }: Identification did not complete within the configured timeout.{ status: 'shed' }: The identify was shed, for example, when usingsheddable: trueand a newer identify superseded it.
Here is the identify call:
Here is what the identify call returns:
You can still await client.identify(context) without inspecting the result if you do not need to handle errors or timeouts explicitly.
Changes to events
Version 4.0 of the SDK includes changes to the allFlags() method and the sendEvents configuration.
Changes to analytics events
In v4.0 of the SDK, the allFlags() method no longer sends analytics events. To learn more, read Getting all flags.
Changes to sending events
In v4.0 of the SDK, you can disable sending events by setting the sendEvents configuration to false.
Flag listener changes
In v4.0 of the SDK, flag listeners have changed in the following ways:
- The
changeevent listener now receives(context, changedKeys), wherechangedKeysis an array of strings. The SDK no longer returns the flag value object along with this event. - The event does not include flag values. You must call
variation()to get the current value. change:<example-flag-key>event listener now only receives(context).
Here is the new flag listener method:
Runtime connection-mode control
Version 4.0 starts in the mode initialConnectionMode specifies. The default mode is streaming. You can change the mode at runtime using setConnectionMode, and the current mode read back using getConnectionMode. Valid modes are offline, streaming, and polling.
Here is an example:
Version 3.x is configuration-only and has no runtime control over connection mode.
Storage configuration
Version 4.0 configures the persistent cache, which includes anonymous-key persistence and last-known flag values, using a storage option on LDOptions. The option accepts any object that satisfies the Storage interface, including get, set, and clear, replacing the previous localStoragePath field.
Omitting storage uses the built-in file-backed cache at <cwd>/ldclient-user-cache:
To set up custom storage implementation:
Persistent cache format
The on-disk cache used by anonymous-key persistence and last-known flag values changed format:
- Version 3.x stored entries using
node-localstorage, with one file per key inside<localStoragePath>/ldclient-user-cache/ - Version 4.0 stores all entries in a single
<localStoragePath>/ldclient-user-cache/ldcache.jsonfile
The default location <cwd>/ldclient-user-cache is unchanged, but existing v3.x cache data will not be read. The next anonymous identify will generate a fresh anonymous key. Existing flag values will repopulate from the network on the next sync.
Secure mode hash
Version 3.x accepted the secure mode hash as a positional second argument to identify().
Version 4.0 accepts the hash both at construction time as a static default
and per-identify using LDIdentifyOptions. When you provide a per-identify hash, it takes precedence over the config-level value for that call and all subsequent network requests until the next identify.
Here is an example:
If your application never needs to rotate the hash, pass it once in LDOptions and omit it from individual identify calls.
Mobile key support
By default, createClient treats the first argument as a client-side ID. To authenticate with a mobile key instead, set useMobileKey: true.
Here is an example:
useMobileKey defaults to false, so existing code that passes a client-side ID continues to work without changes.
Mobile keys do not support secure mode. Setting both useMobileKey: true and hash (the secure mode hash) causes createClient to throw at construction time:
Removed dependencies
These dependencies were removed in v4.0:
node-localstoragewas replaced by an in-tree fs-backed implementation
What was deprecated
All types and methods that were marked as deprecated in the last 3.x release have been removed from the 4.0 release. If you were using these with a recent version previously, you should already have received deprecation warnings at compile time, with suggestions about their recommended replacements.
For a full list of deprecated types and methods, read the release notes in GitHub.