LaunchDarkly Developer Documentation

Get started in under 30 minutes.
LaunchDarkly provides feature flags as a service for Java · Python · Ruby · Go · Node.js · PHP · .NET. Control feature launches -- who sees what and when -- without multiple code deploys. Easy dashboard for phased rollouts, targeting and segmenting.
Need more help? write us at support@launchdarkly.com

Get Started    Documentation

Using a persistent feature store

In their default configuration, the server-side SDKs work as follows: they connect to LaunchDarkly and receive feature flag data; they store the flags in memory; if LaunchDarkly sends any flag updates, they update the in-memory state; and flag evaluations always refer to the last known state in memory. This collection of last known flag data is the "feature store."

It is also possible to use a database for the feature store. All of the SDKs support Redis for this purpose, and other database integrations are being added—see the individual database sections below for more details on each. Whichever database you use, there are two ways to use it:

  • Exactly like the default configuration, except substituting a database for the in-memory store;
  • Or, using only the database as a source of flag data, without connecting to LaunchDarkly.

Using a persistent feature store while still connecting to LaunchDarkly

In this configuration, the SDK still receives feature flag data from LaunchDarkly and puts it in the feature store; the only difference is that the store is in a database. When flags are evaluated, the SDK checks the database to get the latest flag state (usually with some form of in-memory caching to improve performance).

The main reason for doing this is to help with the case where your application has to restart, and after restarting, it is for some reason taking a while to establish a LaunchDarkly connection. If you have a persistent feature store that has already been populated, then the SDK can still evaluate flags using the last known flag state from the store until newer data is available from LaunchDarkly.

To do this, you will generally create some kind of object for the specific type of database (see individual database sections below) and put it in the feature store property (or in PHP, "feature requester") of the client configuration:

import ld "gopkg.in/launchdarkly/go-server-sdk.v4"

store, err := somepackage.NewSomeKindOfFeatureStore(storeOptions)
config := ld.DefaultConfig
config.FeatureStore = store
client := ld.MakeCustomClient(sdkKey, config, waitTime)
import com.launchdarkly.client.*;

FeatureStoreFactory store = SomeKindOfFeatureStoreBuilder(storeOptions);
Config config = new Config.Builder()
    .featureStoreFactory(store)
    .build();
LDClient client = new LDClient(sdkKey, config);
using LaunchDarkly.Client;

var store = createSomeKindOfFeatureStore();
var config = Configuration.Default(sdkKey)
    .WithFeatureStoreFactory(store);
var client = new LDClient(config);
require 'ldclient-rb'

store = SomeKindOfFeatureStore.new(storeOptions)
config = LaunchDarkly::Config.new(
  feature_store: store
)
client = LaunchDarkly::Client.new(sdk_key, config)
import ldclient
from ldclient.config import Config

store = SomeKindOfFeatureStore(store_options)
config = Config(feature_store=store)
ldclient.set_config(config)
const LaunchDarkly = require('ldclient-node');

const store = SomeKindOfFeatureStore(storeOptions);
const config = {
  featureStore: store
};
const client = LaunchDarkly.init(sdkKey, config);
$client = new LaunchDarkly\LDClient("your_sdk_key", [
    'feature_requester' => LaunchDarkly\Integrations\Redis::featureRequester()
]);

// Prior to version 3.5.0, use this syntax:
// $client = new LaunchDarkly\LDClient("your_sdk_key", [
//     'feature_requester_class' => 'LaunchDarkly\SomeKindOfFeatureRequester'
// ]);

Note that if there are multiple instances of your application configured in this way with the same database, the same data will be written to the database repeatedly as the instances all receive feature flags from LaunchDarkly. This is harmless, but it is inefficient, so you may want to consider the following configuration instead:

Using a persistent feature store without connecting to LaunchDarkly

This is similar to the previous configuration, except that the SDK does not connect to LaunchDarkly at all. Instead, it relies on some other process which does have a LaunchDarkly connection to write the latest flag data to the database, where the SDK will then read it.

The other process could be the LaunchDarkly relay proxy, or any other application that creates a SDK client with the same persistent store (as in the previous configuration). Since the relay proxy is also known as the LaunchDarkly Daemon when it is used in this way, the SDKs generally refer to this mode as "LDD mode." Creating the client is the same as above except for specifying LDD mode:

import ld "gopkg.in/launchdarkly/go-server-sdk.v4"

store, err := somepackage.NewSomeKindOfFeatureStore(storeOptions)
config := ld.DefaultConfig
config.FeatureStore = store
config.UseLdd = true
client := ld.MakeCustomClient(sdkKey, config, waitTime)
import com.launchdarkly.client.*;

FeatureStoreFactory store = SomeKindOfFeatureStoreBuilder(storeOptions);
Config config = new Config.Builder()
    .featureStoreFactory(store)
    .useLdd(true)
    .build();
LDClient client = new LDClient(sdkKey, config);
using LaunchDarkly.Client;

var store = createSomeKindOfFeatureStore();
var config = Configuration.Default(sdkKey)
    .WithFeatureStoreFactory(store)
    .WithUseLdd(true);
var client = new LDClient(config);
require 'ldclient-rb'

store = SomeKindOfFeatureStore.new(storeOptions)
config = LaunchDarkly::Config.new(
  feature_store: store,
  use_ldd: true
)
client = LaunchDarkly::Client.new(sdk_key, config)
import ldclient
from ldclient.config import Config

store = SomeKindOfFeatureStore(store_options)
config = Config(feature_store=store, use_ldd=True)
ldclient.set_config(config)
const LaunchDarkly = require('ldclient-node');

const store = SomeKindOfFeatureStore(storeOptions);
const config = {
  featureStore: store,
  useLdd: true
};
const client = LaunchDarkly.init(sdkKey, config);
/*
  In PHP, there is no difference between this and the previous example, because
  the PHP SDK can only either get flags from LaunchDarkly *or* get them from a
  database, not both
*/
$client = new LaunchDarkly\LDClient("your_sdk_key", [
    'feature_requester' => LaunchDarkly\Integrations\Redis::featureRequester()
]);

// Prior to version 3.5.0, use this syntax:
// $client = new LaunchDarkly\LDClient("your_sdk_key", [
//     'feature_requester_class' => 'LaunchDarkly\SomeKindOfFeatureRequester'
// ]);

Using Redis

All of the LaunchDarkly server-side SDKs support Redis. This feature is built into the main SDK distribution in all cases except .NET, where it requires a separate package.

The available options are slightly different in each language, but you can always specify the following:

  • The Redis host address (defaults to localhost:6379).
  • A prefix string to add to all keys used by the store, to avoid collisions in case the database is also being used for some other purpose.
  • The length of time that recently read or updated data should be cached in memory.

In the following examples, the Redis feature store is set to use a host address of my-redis:6379, a prefix string of "my-key-prefix", and a cache TTL of 30 seconds.

import (
    ld "gopkg.in/launchdarkly/go-server-sdk.v4"
    ldredis "gopkg.in/launchdarkly/go-server-sdk.v4/redis"
)

store, err := ldredis.NewRedisFeatureStoreWithDefaults(
    ldredis.HostAndPort("my-redis", 6379),
    ldredis.Prefix("my-key-prefix"),
    ldredis.CacheTTL(30 * time.Second))

config := ld.DefaultConfig
config.FeatureStore = store
client := ld.MakeCustomClient(sdkKey, config, waitTime)
import com.launchdarkly.client.*;

FeatureStoreFactory store =
    Components.redisFeatureStore(URI.create("redis://my-redis:6379"))
        .prefix("my-key-prefix")
        .cacheTime(30, TimeUnit.SECONDS);

Config config = new Config.Builder()
    .featureStoreFactory(store)
    .build();
LDClient client = new LDClient(sdkKey, config);
// Requires this package: https://github.com/launchdarkly/dotnet-server-sdk-redis

using LaunchDarkly.Client;
using LaunchDarkly.Client.Redis;

var store = RedisComponents.RedisFeatureStore()
    .WithRedisHostAndPort("my-redis", 6379)
    .WithPrefix("my-key-prefix")
    .WithCacheExpiration(TimeSpan.FromSeconds(30));

var config = Configuration.Default(sdkKey)
    .WithFeatureStoreFactory(store);
var client = new LDClient(config);
# Requires the additional gems 'redis' and 'connection_pool'

require 'ldclient-rb'

store = LaunchDarkly::Integrations::Redis.new_feature_store(
  redis_url: 'redis://my-redis:6379',
  prefix: 'my-key-prefix',
  expiration: 30
)

# Prior to version 5.5.0, use "LaunchDarkly::RedisFeatureStore.new" instead
# of "LaunchDarkly::Integrations::Redis.new_feature_store"

config = LaunchDarkly::Config.new(
  feature_store: store
)
client = LaunchDarkly::Client.new(sdk_key, config)
import ldclient
from ldclient.config import Config
from ldclient.feature_store import CacheConfig
from ldclient.integrations import Redis

store = Redis.new_feature_store(url='redis://my-redis:6379',
    prefix='my-key-prefix', caching=CacheConfig(expiration=30))

# Prior to version 6.7.0, use this syntax:
# store = RedisFeatureStore(url='redis://my-redis:6379', prefix='my-key-prefix',
#     expiration=30)

config = Config(feature_store=store)
ldclient.set_config(config)
const LaunchDarkly = require('ldclient-node');

const redisOpts = {
  url: 'redis://my-redis:6379'
};
const store = LaunchDarkly.RedisFeatureStore(redisOpts, 30, 'my-key-prefix');

const config = {
  featureStore: store
};
const client = LaunchDarkly.init(sdkKey, config);
/*
  Note that there is no parameter for the cache TTL; the PHP SDK does not cache
  data from Redis, since in PHP the entire in-memory application state is
  normally discarded after each request.

  Also, you must install the package "predis/predis".
*/
$fr = LaunchDarkly\Integrations\Redis::featureRequester([
    'redis_host' => 'my-redis',
    'redis_port' => 6379,
    'redis_prefix' => 'my-key-prefix'
]);
$client = new LaunchDarkly\LDClient("your_sdk_key", [
    'feature_requester' => $fr
]);

// Prior to version 3.5.0, use this syntax:
// $client = new LaunchDarkly\LDClient("your_sdk_key", [
//     'feature_requester_class' => 'LaunchDarkly\LDDFeatureRequester',
//     'redis_host' => 'my-redis',
//     'redis_port' => 6379,
//     'redis_prefix' => 'my-key-prefix'
// ]);

Using DynamoDB

All of the current versions of the server-side SDKs support DynamoDB. DynamoDB is a particularly useful solution if you are running code in AWS Lambda, since it can be accessed from Lambda without needing access to any VPC resource.

In the Go SDK (as of version 4.5.1), the Ruby SDK (as of version 5.5.1), the Python SDK (as of version 6.7.0), and the PHP SDK (as of version 3.5.0), this feature is built into the main SDK distribution. The other SDKs require an additional package: Java, .NET, Node.js.

In your application code, the only required parameter is the table name, although you can also specify any other options supported by AWS; by default, the DynamoDB driver will expect to get your AWS credentials and region from environment variables or local configuration files, as described in the AWS SDK documentation.

The table must already exist before your application starts. It must have a partition key called "namespace", and a sort key called "key". (The SDK does not create the table automatically because it would not know what values to use for other properties such as permissions and throughput.)

Note that DynamoDB imposes a limit of 400KB on the total size of any database item. In this implementation, each feature flag (or user segment) is a single item, so the feature store will not be able to persist any flag or segment whose JSON representation is larger than that limit.

In the following examples, the DynamoDB feature store is set to use a table called "my-table" and a cache TTL of 30 seconds. (The DynamoDB feature store does support using a key prefix, as shown in the Redis examples, but it is uncommon for one DynamoDB table to be shared by multiple applications.)

import (
    ld "gopkg.in/launchdarkly/go-server-sdk.v4"
    "gopkg.in/launchdarkly/go-server-sdk.v4/lddynamodb"
)

store, err := ldredis.NewDynamoDBFeatureStore("my-table",
    lddynamodb.CacheTTL(30 * time.Second))

config := ld.DefaultConfig
config.FeatureStore = store
client := ld.MakeCustomClient(sdkKey, config, waitTime)
// Requires this package: https://github.com/launchdarkly/java-server-sdk-dynamodb

import com.launchdarkly.client.*;
import com.launchdarkly.client.dynamodb.*;

FeatureStoreFactory store =
    DynamoDbComponents.dynamoDbFeatureStore("my-table")
        .caching(FeatureStoreCacheConfig.enabled().withTtlSeconds(30));

Config config = new Config.Builder()
    .featureStoreFactory(store)
    .build();
LDClient client = new LDClient(sdkKey, config);
// Requires this package: https://github.com/launchdarkly/dotnet-server-sdk-dynamodb

using LaunchDarkly.Client;
using LaunchDarkly.Client.DynamoDB;

var store = DynamoDBComponents.DynamoDBFeatureStore("my-table")
    .WithCaching(FeatureStoreCacheConfig.Enabled.WithTtlSeconds(30));

var config = Configuration.Default(sdkKey)
    .WithFeatureStoreFactory(store);
var client = new LDClient(config);
# Requires the additional gem 'aws-sdk-dynamodb'

require 'ldclient-rb'

store = LaunchDarkly::Integrations::DynamoDB.new_feature_store('my-table',
  { expiration: 30 })

config = LaunchDarkly::Config.new(
  feature_store: store
)
client = LaunchDarkly::Client.new(sdk_key, config)
# Requires the additional package 'boto3'

import ldclient
from ldclient.config import Config
from ldclient.feature_store import CacheConfig
from ldclient.integrations import DynamoDB

store = DynamoDB.new_feature_store('my_table',
    caching=CacheConfig(expiration=30))

config = Config(feature_store=store)
ldclient.set_config(config)
// Requires this package: https://github.com/launchdarkly/node-server-sdk-dynamodb

const LaunchDarkly = require('ldclient-node');
const DynamoDBFeatureStore = require('ldclient-node-dynamodb-store');

const store = DynamoDBFeatureStore('my-table', { cacheTTL: 30 });

const config = {
  featureStore: store
};
const client = LaunchDarkly.init(sdkKey, config);
/*
  Note that there is no parameter for the cache TTL; the PHP SDK does not cache
  data from DynamoDB, since in PHP the entire in-memory application state is
  normally discarded after each request.

  Also, you must install the package "aws/aws-sdk-php".
*/
$fr = LaunchDarkly\Integrations\DynamoDb::featureRequester([
    'dynamodb_table' => 'my-table'
]);
$client = new LaunchDarkly\LDClient("your_sdk_key", [
    'feature_requester' => $fr
]);

Using Consul

All of the current versions of the server-side SDKs support Consul. In the Go SDK (as of version 4.5.0), the Ruby SDK (as of version 5.5.1), the Python SDK (as of version 6.8.1), and the PHP SDK (as of version 3.5.0), this feature is built into the main SDK distribution. The other SDKs require an additional package: Java, .NET, Node.js.

In the following examples, the Consul feature store is set to use a host address of my-consul:8100, a prefix string of "my-key-prefix", and a cache TTL of 30 seconds.

import (
    ld "gopkg.in/launchdarkly/go-server-sdk.v4"
    "gopkg.in/launchdarkly/go-server-sdk.v4/ldconsul"
)

store, err := ldconsul.NewConsulFeatureStore(
    ldconsul.Address("http://my-consul:8100"),
    ldconsul.Prefix("my-key-prefix"),
    ldconsul.CacheTTL(30 * time.Second))

config := ld.DefaultConfig
config.FeatureStore = store
client := ld.MakeCustomClient(sdkKey, config, waitTime)
// Requires this package: https://github.com/launchdarkly/java-server-sdk-consul

import com.launchdarkly.client.*;
import com.launchdarkly.client.consul.*;

FeatureStoreFactory store =
    ConsulComponents.consulFeatureStore()
        .url(URL.create("http://my-consul:8100"))
        .prefix("my-key-prefix")
        .caching(FeatureStoreCacheConfig.enabled().withTtlSeconds(30));

Config config = new Config.Builder()
    .featureStoreFactory(store)
    .build();
LDClient client = new LDClient(sdkKey, config);
// Requires this package: https://github.com/launchdarkly/dotnet-server-sdk-consul

using LaunchDarkly.Client;
using LaunchDarkly.Client.Consul;

var store = ConsulComponents.ConsulFeatureStore()
    .WithAddress(new Uri("http://my-consul:8100"))
    .WithCaching(FeatureStoreCacheConfig.Enabled.WithTtlSeconds(30));

var config = Configuration.Default(sdkKey)
    .WithFeatureStoreFactory(store);
var client = new LDClient(config);
# Requires the additional gem 'diplomat'

require 'ldclient-rb'

store = LaunchDarkly::Integrations::Consul.new_feature_store(
  { url: 'http://my-consul:8100', prefix: 'my-key-prefix', expiration: 30 })

config = LaunchDarkly::Config.new(
  feature_store: store
)
client = LaunchDarkly::Client.new(sdk_key, config)
# Requires the additional package 'python-consul' - note that this is not
# compatible with Python 3.3 or 3.4.

import ldclient
from ldclient.config import Config
from ldclient.feature_store import CacheConfig
from ldclient.integrations import Consul

store = Consul.new_feature_store(host='my-consul', port=8100,
    prefix='my-key-prefix', caching=CacheConfig(expiration=30))

config = Config(feature_store=store)
ldclient.set_config(config)
// Requires this package: https://github.com/launchdarkly/node-server-sdk-consul

const LaunchDarkly = require('ldclient-node');
const ConsulFeatureStore = require('ldclient-node-consul-store');

const store = ConsulFeatureStore({
  consulOptions: {
    host: 'my-consul',
    port:  8100
  },
  prefix: 'my-key-prefix',
  cacheTTL: 30
});

const config = {
  featureStore: store
};
const client = LaunchDarkly.init(sdkKey, config);
/*
  Note that there is no parameter for the cache TTL; the PHP SDK does not cache
  data from Consul, since in PHP the entire in-memory application state is
  normally discarded after each request.

  Also, you must install the package "sensiolabs/consul-php-sdk".
*/
$fr = LaunchDarkly\Integrations\Consul::featureRequester([
    'consul_uri' => 'http://my-consul:8100',
    'consul_prefix' => 'my-key-prefix'
]);
$client = new LaunchDarkly\LDClient("your_sdk_key", [
    'feature_requester' => $fr
]);

Using a persistent feature store


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.