> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Storing data

<View title="Developer" />

<View title="Federal docs" />

<View title="EU docs" />

This topic explains which external databases each server-side SDK can use to store flag data.

By default, all our SDKs work with an in-memory feature store. This feature store requires no additional configuration. However, data in in-memory feature stores are not persistent. This means when you restart your application, your SDK reloads the entire store's contents.

Persistent feature stores solve this problem by persisting their data so that they can be used across application restarts.

## Using external databases as persistent feature stores

By default, LaunchDarkly's server-side SDKs connect to LaunchDarkly and receive feature flag data, store the flags in local memory, and update them when prompted to by LaunchDarkly. This collection of last known flag data is cached in the "feature store" or "data store", and cached values have no expiration or time-to-live (TTL) value.

To learn more, read [Persistent data stores](/docs/sdk/concepts/data-stores).

Alternatively, you can configure an external database to act as a feature store. The SDKs in this topic can use one or more of these three caching options to hold their flag data:

* [Consul](/docs/sdk/features/storing-data/consul)
* [DynamoDB](/docs/sdk/features/storing-data/dynamodb)
* [Redis](/docs/sdk/features/storing-data/redis)

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 while connecting to LaunchDarkly](#using-a-persistent-feature-store-while-still-connecting-to-launchdarkly), or
* Using [*only* the database as a source of flag data, without connecting to LaunchDarkly](#using-a-persistent-feature-store-without-connecting-to-launchdarkly).

In both configurations, you can control when the SDK checks the database, as opposed to in-memory caching, using the cache time-to-live (TTL) configuration option for your SDK.

There is a tradeoff here that will be different for each customer. Most customers find that it's generally unacceptable from a performance standpoint to read from the database on every flag evaluation. If you prefer faster evaluations and can accept some stale data, you can have the SDK check the in-memory caching more frequently. If you prefer fresher data and can accept slower evaluations, you can have the SDK check the database more frequently.

As long as the cache is fresh, evaluations will use the cache, even if the external database is unavailable. After the cache expires, the SDK attempts to re-read from the database. If the database is unavailable, the SDK returns flag fallback values.

### Using a persistent feature store while still connecting to LaunchDarkly

In this configuration, the SDK 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. If you have a persistent feature store that has already been populated, the SDK can still evaluate flags using the last known flag state from the store until newer data is available from LaunchDarkly.

To set up this configuration, most people create some kind of object for the specific type of database and put it in the client configuration's feature store property. In PHP, this property is called the "feature requester."

If there are multiple instances of your application configured to store data in the same database, those multiple instances may overwrite each other's data. This is not a problem because each instance receives feature flags from LaunchDarkly, so the copy of the data should be identical. However, it is inefficient. Instead, you may want to use a persistent feature store without connecting to LaunchDarkly, as described below.

### Using a persistent feature store without connecting to LaunchDarkly

This is similar to the previous configuration: When flags are evaluated, the SDK checks the database to get the latest flag state, usually with some form of in-memory caching. However, in this configuration 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 Relay Proxy in offline or daemon mode, or any other application that creates an SDK client with the same persistent store. To learn more about the Relay Proxy, read [The Relay Proxy](/docs/sdk/relay-proxy).

The Relay Proxy is also known as the LaunchDarkly Daemon, so some versions of the SDKs refer to this mode as "LDD mode." Creating the client is the same as above in terms of specifying the persistent store, but you must also add an option to make the SDK *not* connect to LaunchDarkly.

## Server-side SDKs

This feature is available in the following server-side SDKs:

* [.NET (server-side)](#net-server-side)
* [C++ (server-side)](#c++-server-side)
* [Erlang](#erlang)
* [Go](#go)
* [Haskell](#haskell)
* [Java](#java)
* [Lua](#lua)
* [Node.js (server-side)](#node-js-server-side)
* [PHP](#php)
* [Python](#python)
* [Ruby](#ruby)

### .NET (server-side)

<Accordion title="Expand .NET (server-side) code sample">
  The .NET SDK can use [Consul](/docs/sdk/features/storing-data/consul#net-server-side), [DynamoDB](/docs/sdk/features/storing-data/dynamodb#net-server-side), or [Redis](/docs/sdk/features/storing-data/redis#net-server-side) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```csharp title=".NET SDK DataStore" lines wrap theme={null}
    using LaunchDarkly.Sdk.Server;
    using LaunchDarkly.Sdk.Server.Integrations;

    var config = Configuration.Builder(sdkKey)
        .DataStore(
            Components.PersistentDataStore(
                SomeDatabaseName.DataStore()
            )
        )
        .Build();
    ```
  </CodeGroup>

  To learn more, read [`ConfigurationBuilder.DataStore`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.ConfigurationBuilder.html#DataStore).

  If you are using the newer DataSystem configuration added in .NET SDK 8.11+, use the `DataSystem` builder with `Components.DataSystem().PersistentStore()` to configure the persistent store:

  <CodeGroup>
    ```csharp title=".NET SDK 8.11+ DataSystem" lines wrap theme={null}
    var config = Configuration.Builder("YOUR_SDK_KEY")
        .DataSystem(
            Components.DataSystem().PersistentStore(
                Components.PersistentDataStore(Redis.DataStore())
            )
        )
        .Build();
    ```
  </CodeGroup>

  To learn more, read [`DataSystemBuilder`](https://launchdarkly.github.io/dotnet-core/pkgs/sdk/server/api/LaunchDarkly.Sdk.Server.Integrations.DataSystemBuilder.html) for additional configuration options.

  To use a persistent feature store without connecting to LaunchDarkly, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#net-server-side).

  For configurations using the `DataSystem` in which the SDK will write to the `PersistentStore`, we do not recommend using an infinite TTL as this provides no benefit and will increase memory usage.
</Accordion>

### C++ (server-side)

<Accordion title="Expand C++ (server-side) code sample">
  The C++ SDK can use [DynamoDB](/docs/sdk/features/storing-data/dynamodb#c++-server-side) or [Redis](/docs/sdk/features/storing-data/redis#c++-server-side) to hold flag data.

  In the C++ SDK v3.0, you cannot use a persistent feature store while connecting to LaunchDarkly.

  To use a persistent feature store without having the SDK connect to LaunchDarkly, use the `LazyLoadBuilder`. The SDK reads flag data from the persistent store lazily, in the background.

  Here's how:

  <CodeGroup>
    ```cpp title="C++ SDK v3.0 (native)" lines wrap theme={null}
    using LazyLoad = server_side::config::builders::LazyLoadBuilder;

    auto config_builder = server_side::ConfigBuilder(sdk_key);

    auto some_source = YourDatabaseIntegration();

    config_builder.DataSystem().Method(
        LazyLoad().Source(some_source)
    );

    auto config = config_builder.Build();
    if (!config) {
        /* an error occurred, config is not valid */
    }
    ```
  </CodeGroup>

  To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#c++-server-side) and [`LazyLoadBuilder`](https://launchdarkly.github.io/cpp-sdks/libs/server-sdk/docs/html/structlaunchdarkly_1_1server__side_1_1config_1_1builders_1_1LazyLoadBuilder.html).
</Accordion>

### Erlang

<Accordion title="Expand Erlang code sample">
  The Erlang SDK can use [Redis](/docs/sdk/features/storing-data/redis#erlang) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```erlang title="Erlang" lines wrap theme={null}
    LdOptions = #{
      feature_store => your_feature_store
    },
    ldclient:start_instance("YOUR_SDK_KEY", LdOptions).
    ```
  </CodeGroup>

  To use a persistent feature store without connecting to LaunchDarkly, set the `feature_store` property as above, and then set the `use_ldd` option to configure daemon mode. To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#erlang).
</Accordion>

### Go

<Accordion title="Expand Go code sample">
  The Go SDK can use [Consul](/docs/sdk/features/storing-data/consul#go), [DynamoDB](/docs/sdk/features/storing-data/dynamodb#go), or [Redis](/docs/sdk/features/storing-data/redis#go) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```go title="Go SDK v6+" lines wrap theme={null}
    import (
        "time"

        ld "github.com/launchdarkly/go-server-sdk/v6"
        "github.com/launchdarkly/go-server-sdk/v6/ldcomponents"
        examplepackage "github.com/launchdarkly/go-server-sdk-some-example-database"
    )

    var config ld.Config
    config.DataStore = ldcomponents.PersistentDataStore(
        examplepackage.DataStore().SomeStoreOptions(),
    )
    client, _ := ld.MakeCustomClient(sdkKey, config, 5*time.Second)
    ```
  </CodeGroup>

  To learn more, read [`PersistentDataStore`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7/ldcomponents#PersistentDataStore).

  To use a persistent feature store without connecting to LaunchDarkly, use `PersistentDataStore()` as above, and then use [`ExternalUpdatesOnly()`](https://pkg.go.dev/github.com/launchdarkly/go-server-sdk/v7/ldcomponents#ExternalUpdatesOnly) to configure daemon mode. To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#go).
</Accordion>

### Haskell

<Accordion title="Expand Haskell code sample">
  The Haskell SDK can use [Redis](/docs/sdk/features/storing-data/redis#haskell) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```haskell title="Haskell" lines wrap theme={null}
    import LaunchDarkly.Server

    main = do
        backend <- makeYourBackendInterface

        let config = configSetStoreBackend backend $ makeConfig "YOUR_SDK_KEY"

        client <- makeClient config
    ```
  </CodeGroup>

  To use a persistent feature store without connecting to LaunchDarkly, use `configSetStoreBackend` as above, and then use `configSetUseLdd` to configure daemon mode. To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#haskell).
</Accordion>

### Java

<Accordion title="Expand Java code sample">
  The Java SDK can use [Consul](/docs/sdk/features/storing-data/consul#java), [DynamoDB](/docs/sdk/features/storing-data/dynamodb#java), or [Redis](/docs/sdk/features/storing-data/redis#java) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```java title="Java" lines wrap theme={null}
    import com.launchdarkly.sdk.server.*;
    import com.launchdarkly.sdk.server.integrations.*;

    LDConfig config = new LDConfig.Builder()
      .dataStore(
        Components.persistentDataStore(
          SomeDatabaseName.dataStore(storeOptions)
        )
      )
      .build();
    LDClient client = new LDClient(sdkKey, config);
    ```
  </CodeGroup>

  To learn more, read [`Components.persistentDataStore`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/Components.html#persistentDataStore-com.launchdarkly.sdk.server.subsystems.ComponentConfigurer-).

  If you are using the newer DataSystem configuration added in Java SDK 7.11+, use the `dataSystem` builder with `Components.dataSystem().persistentStore()` to configure the persistent store:

  <CodeGroup>
    ```java title="Java SDK 7.11+ DataSystem" lines wrap theme={null}
    import com.launchdarkly.sdk.server.*;

    LDConfig config = new LDConfig.Builder()
        .dataSystem(
            Components.dataSystem().persistentStore(
                Components.persistentDataStore(Redis.dataStore())
            )
        )
        .build();

    LDClient client = new LDClient("YOUR_SDK_KEY", config);
    ```
  </CodeGroup>

  To learn more, read [`DataSystemModes`](https://launchdarkly.github.io/java-core/lib/sdk/server/com/launchdarkly/sdk/server/integrations/DataSystemModes.html) for additional configuration options.

  To use a persistent feature store without connecting to LaunchDarkly, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#java).

  For configurations using the `dataSystem` in which the SDK will write to the persistent store, we do not recommend using an infinite TTL as this provides no benefit and will increase memory usage.
</Accordion>

### Lua

<Accordion title="Expand Lua code sample">
  The Lua SDK can use [Redis](/docs/sdk/features/storing-data/redis#lua) to hold flag data. The module `launchdarkly_server_sdk_redis` caches the feature flag data.

  In the Lua SDK v2, you cannot use a persistent feature store while connecting to LaunchDarkly.

  To use a persistent feature store without having the SDK connect to LaunchDarkly, specify a `lazyLoad` data source. The SDK reads flag data from the persistent store lazily, in the background.

  Here's how:

  <CodeGroup>
    ```lua title="Lua SDK v2" lines wrap theme={null}
    local config = {
        dataSystem = {
            lazyLoad = {
                source = makeYourSource()
            }
        }
    }
    ```
  </CodeGroup>

  In the Lua SDK v1, you can use a feature store while connecting to LaunchDarkly.

  <Accordion title="Expand Lua code sample for older versions">
    To use a persistent feature store while connecting to LaunchDarkly:

    <CodeGroup>
      ```lua title="Lua SDK v1.x" lines wrap theme={null}
      local l = require("launchdarkly_server_sdk")

      local backend = makeYourBackendInterface()

      local c = l.clientInit({
          key                 = "YOUR_SDK_KEY",
          featureStoreBackend = backend
      })
      ```
    </CodeGroup>
  </Accordion>

  To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#lua).
</Accordion>

### Node.js (server-side)

<Accordion title="Expand Node.js (server-side) code sample">
  The Node.js SDK can use [Consul](/docs/sdk/features/storing-data/consul#node-js-server-side), [DynamoDB](/docs/sdk/features/storing-data/dynamodb#node-js-server-side), or [Redis](/docs/sdk/features/storing-data/redis#node-js-server-side) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```js title="Node.js SDK v8.x+ (JavaScript)" lines wrap theme={null}
    import { init } from '@launchdarkly/node-server-sdk';

    const store = SomeKindOfFeatureStore(storeOptions);
    const options = {
      featureStore: store
    };
    const client = init('YOUR_SDK_KEY', options);
    ```

    ```ts title="Node.js SDK v8.x+ (TypeScript)" lines wrap theme={null}
    import { LDOptions, init } from '@launchdarkly/node-server-sdk';

    const store = SomeKindOfFeatureStore(storeOptions);

    const options: LDOptions = {
      featureStore: store,
    };
    const client = init('YOUR_SDK_KEY', options);
    ```
  </CodeGroup>

  To use a persistent feature store without connecting to LaunchDarkly, set the `featureStore` property as above, and then set the `useLdd` property to configure daemon mode. To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#node-js-server-side).
</Accordion>

### PHP

<Accordion title="Expand PHP code sample">
  The PHP SDK can use [Consul](/docs/sdk/features/storing-data/consul), [DynamoDB](/docs/sdk/features/storing-data/dynamodb), or [Redis](/docs/sdk/features/storing-data/redis) to get flag data.

  Unlike other server-side SDKs, the PHP SDK cannot connect to LaunchDarkly while using a database as a backing store. It can only read from a database that has been populated by the [Relay Proxy](/docs/sdk/relay-proxy), or by another application that uses a server-side LaunchDarkly SDK. To learn more, read [Using daemon mode](/docs/sdk/relay-proxy/sdk-config#using-daemon-mode).

  Another difference from other SDKs is that the PHP SDK does not have an in-memory cache for database queries. This is because in PHP, the entire in-memory application state is normally discarded after each request. Therefore, code examples for PHP do not include a cache TTL parameter.

  To read from a persistent feature store without connecting to LaunchDarkly:

  <CodeGroup>
    ```php title="PHP" lines wrap theme={null}
    $client = new LaunchDarkly\LDClient("YOUR_SDK_KEY", [
        'feature_requester' => LaunchDarkly\Integrations\NameOfDatabase::featureRequester()
    ]);
    ```
  </CodeGroup>

  Prior to version 4.0, the database integrations were included in the main PHP SDK package. Starting in version 4.0, they are in separate packages.
</Accordion>

### Python

<Accordion title="Expand Python code sample">
  The Python SDK can use [Consul](/docs/sdk/features/storing-data/consul), [DynamoDB](/docs/sdk/features/storing-data/dynamodb), or [Redis](/docs/sdk/features/storing-data/redis) to hold flag data.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```python title="Python" lines wrap theme={null}
    import ldclient
    from ldclient.config import Config

    store = SomeKindOfFeatureStore(store_options)
    config = Config(feature_store=store)
    ldclient.set_config(config)
    ```
  </CodeGroup>

  To use a persistent feature store without connecting to LaunchDarkly, set the `feature_store` property as above, and then set the `use_ldd` property to configure daemon mode. To learn more, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#python).
</Accordion>

### Ruby

<Accordion title="Expand Ruby code sample">
  The Ruby SDK can use [Consul](/docs/sdk/features/storing-data/consul), [DynamoDB](/docs/sdk/features/storing-data/dynamodb), or [Redis](/docs/sdk/features/storing-data/redis) to hold flag data.

  These adapters are implemented in the `LaunchDarkly::Integrations::Redis`, `LaunchDarkly::Integrations::DynamoDB`, and `LaunchDarkly::Integrations::Consul` modules. To use them, call the `new_feature_store` method in the module, and put the returned object in the `feature_store` property of your client configuration.

  To use a persistent feature store while connecting to LaunchDarkly:

  <CodeGroup>
    ```ruby title="Ruby SDK feature_store" lines wrap theme={null}
    require 'ldclient-rb'

    store = SomeKindOfFeatureStore.new(storeOptions)
    config = LaunchDarkly::Config.new(
      feature_store: store
    )
    client = LaunchDarkly::LDClient.new(sdk_key, config)
    ```
  </CodeGroup>

  If you are using the newer DataSystem configuration added in Ruby SDK 8.12.0+, use the `data_system_config` option with `LaunchDarkly::DataSystem.persistent_store()` to configure the persistent store:

  <CodeGroup>
    ```ruby title="Ruby SDK 8.12.0+ DataSystem" lines wrap theme={null}
    require 'ldclient-rb'

    store = SomeKindOfFeatureStore.new(storeOptions)

    config = LaunchDarkly::Config.new(
      data_system_config: LaunchDarkly::DataSystem.persistent_store(store).build
    )

    client = LaunchDarkly::LDClient.new("YOUR_SDK_KEY", config)
    ```
  </CodeGroup>

  To learn more, read [`LaunchDarkly::DataSystem`](https://launchdarkly.github.io/ruby-server-sdk/LaunchDarkly/DataSystem.html) for additional configuration options.

  To use a persistent feature store without connecting to LaunchDarkly, read [Using daemon mode](/docs/sdk/features/relay-proxy-configuration/daemon-mode#ruby).
</Accordion>
