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

# Local Resolution

> Reference documentation for in-process and self-hosted flag resolution.

export const HowToSchema = ({name, description, steps = []}) => {
  const schema = {
    "@context": "https://schema.org",
    "@type": "HowTo",
    name,
    description
  };
  if (steps.length > 0) {
    schema.step = steps.map((s, i) => ({
      "@type": "HowToStep",
      position: i + 1,
      name: typeof s === "string" ? s : s.name,
      text: typeof s === "string" ? s : s.text || s.name
    }));
  }
  return <script type="application/ld+json" dangerouslySetInnerHTML={{
    __html: JSON.stringify(schema)
  }} />;
};

<HowToSchema
  name="Set Up a Self-Hosted Resolver"
  description="Learn how to configure and deploy a self-hosted resolver in your network."
  steps={[
"Create API client credentials",
"Create a self-hosted resolver configuration",
"Store the deployment values securely",
"Run the resolver",
"Configure your SDK",
]}
/>

Local resolve providers resolve flags locally within your application using the [OpenFeature](https://openfeature.dev/) specification. The provider fetches all flag and segment state from Confidence and stores it locally. Flag evaluations happen in-process—no network call at resolve time.

Local resolve providers are available for:

* Go
* Java
* JavaScript/TypeScript
* Python
* Rust

## How It Works

The local resolve provider periodically fetches the resolver state for a given client from Confidence. This state contains all flags, segments, targeting rules, and bloom filters for that client. When your application evaluates a flag, the provider resolves it locally against the cached state.

This approach provides fast, predictable response times and removes the dependency on network availability at evaluation time.

## SDK Configuration

Configure the local resolve provider in your SDK. For example, with the JavaScript server SDK:

```typescript theme={null}
import { OpenFeature } from '@openfeature/server-sdk';
import { createConfidenceServerProvider } from '@spotify-confidence/openfeature-server-provider-local';

const provider = createConfidenceServerProvider({
  flagClientSecret: process.env.CONFIDENCE_FLAG_CLIENT_SECRET,
});

try {
  await OpenFeature.setProviderAndWait(provider);
} catch (e) {
  console.error('Failed to initialize Confidence provider', e);
}

const client = OpenFeature.getClient();
const value = await client.getBooleanValue('my-feature-flag.enabled', false, context);
```

See the [SDK documentation](/docs/reference/sdks/overview) for configuration examples in other languages.

## Materialized Segments

Local resolve providers support [materialized segments](/docs/capabilities/segments/materialized-segments) via bloom filters. When a materialized segment contains up to \~100,000 entities, the resolver state includes its bloom filter and the provider checks membership locally. Larger segments fall back to key-value store lookup over the network.

Bloom filters require no additional setup—Confidence builds and delivers them automatically as part of the resolver state.

## Sticky Assignments

If you want to use sticky assignments with a local resolver, you need access to a low latency key-value storage that can store mappings between entity IDs and variants. Reach out to Confidence support for more information!

<div id="sidecar-resolver" />

## Self-Hosted Resolver

As an alternative to SDK providers, you can run a self-hosted resolver in your network. The resolver exposes the flag resolution API over HTTP. Configure your SDKs to use the resolve URL you host instead of the Confidence managed resolver.

You can operate it as a standalone service or run the container as a sidecar alongside your application. Run it as a sidecar when each application instance needs a resolver on `localhost`.

The self-hosted resolver downloads encrypted flag state from a state URI created in Confidence. It decrypts and caches the state in memory. By default, it checks for updates every 30 seconds and keeps the last successfully loaded state if a refresh fails.

<Note>
  The self-hosted resolver does not support bloom filters for materialized segments. It requires a low latency key-value store for materialized segment lookups.
</Note>

A sidecar deployment is typically available at `http://localhost:8090`. Configure the SDK to use it:

```javascript highlight={3} theme={null}
const confidence = Confidence.create({
  clientSecret: '<flags-client-secret>',
  resolveBaseUrl: 'http://localhost:8090',
  ...
});
```

Use the address of your resolver service when you run it as a shared deployment.

### Create API Client Credentials

The resolver uses API client credentials to authenticate with Confidence and report operational data.

<Steps>
  <Step title="Go to API clients">
    In Confidence, select **Admin**, then select **API clients** under **Identity and access management**.
  </Step>

  <Step title="Create an API client">
    Select **Create** and enter a name, such as "self-hosted resolver."
  </Step>

  <Step title="Assign the resolver role">
    Go to **Admin > Policies** and create a policy for the API client. Assign the **Flags Resolver Sidecar** role.
  </Step>

  <Step title="Store the credentials">
    Store the client ID and client secret in your secret manager.
  </Step>
</Steps>

<Note>
  **Flags Resolver Sidecar** is the current name of the predefined role. The role applies whether you deploy the resolver as a shared service or a sidecar.
</Note>

### Create a Resolver Configuration

The resolver configuration provides an encrypted state file. Confidence keeps the state file up to date as your flags and targeting rules change.

<Steps>
  <Step title="Go to self-hosted resolver configurations">
    In Confidence, select **Admin**, then select **Self-hosted resolver configurations** under **Identity and access management**.
  </Step>

  <Step title="Create a configuration">
    Select **Create configuration**, enter a display name, and select **Create**.
  </Step>

  <Step title="Store the deployment values">
    Copy the state URI and reveal the encryption key. Store both values in your secret manager.
  </Step>
</Steps>

<Warning>
  Treat the state URI and encryption key as secrets. The URI can contain signed query parameters. Don't print the complete URI in logs or diagnostics.
</Warning>

### Run With Docker

Save the four deployment values in `confidence-resolver.env`:

```dotenv theme={null}
CONFIDENCE_RESOLVER_STATE_URL=<state URI>
CONFIDENCE_RESOLVER_STATE_ENCRYPTION_KEY=<encryption key>
CONFIDENCE_CLIENT_ID=<client ID>
CONFIDENCE_CLIENT_SECRET=<client secret>
```

The state encryption key must be a 64-character hexadecimal key. Run the resolver without adding secrets to your shell history:

```bash theme={null}
docker run --rm \
  -p 8090:8090 \
  --env-file ./confidence-resolver.env \
  europe-docker.pkg.dev/spotify-confidence/public/flags-resolver-sidecar:latest
```

The resolver is available at `http://localhost:8090`.

The example uses the Europe Artifact Registry mirror. You can instead use the Asia or United States mirror:

* `asia-docker.pkg.dev/spotify-confidence/public/flags-resolver-sidecar:latest`
* `us-docker.pkg.dev/spotify-confidence/public/flags-resolver-sidecar:latest`

The registry region only determines which mirror serves the image.

### Deploy in Kubernetes

You can run the resolver as a shared Kubernetes service or as a sidecar. The following example adds it as a sidecar to an existing pod:

```yaml theme={null}
spec:
  containers:
    - name: my-service
      image: gcr.io/my-service/image:latest

    - name: confidence-resolver
      image: europe-docker.pkg.dev/spotify-confidence/public/flags-resolver-sidecar:latest
      env:
        - name: CONFIDENCE_RESOLVER_STATE_URL
          valueFrom:
            secretKeyRef:
              name: confidence-resolver-state
              key: url
        - name: CONFIDENCE_RESOLVER_STATE_ENCRYPTION_KEY
          valueFrom:
            secretKeyRef:
              name: confidence-resolver-state
              key: encryption-key
        - name: CONFIDENCE_CLIENT_ID
          valueFrom:
            secretKeyRef:
              name: confidence-api-client
              key: client-id
        - name: CONFIDENCE_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              name: confidence-api-client
              key: client-secret
      ports:
        - name: http
          containerPort: 8090
      readinessProbe:
        exec:
          command: ["/bin/grpc_health_probe", "-addr=:5990"]
        initialDelaySeconds: 5
      livenessProbe:
        exec:
          command: ["/bin/grpc_health_probe", "-addr=:5990"]
        initialDelaySeconds: 10
      resources:
        requests:
          cpu: 1
          memory: 256M
        limits:
          cpu: 2
          memory: 512M
```

The resolver becomes ready after it downloads and decrypts its first state file. It checks for new state every 30 seconds by default. It uses the state file's `ETag` in conditional requests. An HTTP `304 Not Modified` response skips the reload. If a later refresh fails, the resolver continues to use the last successfully loaded state.

### Rotate State Credentials

Rotate the state URI and encryption key without interrupting flag resolution:

<Steps>
  <Step title="Start credentials rotation">
    Open the menu for the active configuration and select **Start credentials rotation**. The existing configuration remains published.
  </Step>

  <Step title="Create the replacement">
    Create a replacement configuration and store its state URI and encryption key.
  </Step>

  <Step title="Deploy the replacement values">
    Update your resolver deployment. Confirm that every instance is ready and uses the replacement configuration.
  </Step>

  <Step title="Complete the sunset">
    Open the retiring configuration's menu and select **Complete sunset**.
  </Step>
</Steps>

<Warning>
  Completing the sunset stops publication of that configuration. Its encryption key might no longer be available. You can't reverse this action.
</Warning>

### Stop Apply Log Propagation

By default, the resolver sends apply logs to Confidence for exposure and experiment analysis. Set `CONFIDENCE_SEND_APPLY_LOGS` to `false` to keep apply data within your network.

The resolver continues to accept and validate `ApplyFlags` requests. It doesn't send assignment events or apply distinct counts to Confidence. It continues to send aggregate operational metadata, including the apply request rate.

<Warning>
  Disabling apply logs degrades Confidence functionality. Confidence can't observe which entities were exposed to each variant. Exposure counts, experiment results, and rollout monitoring will be missing or incomplete.
</Warning>

This setting doesn't disable resolve telemetry or resolver-state synchronization. For more information, see [Data Transfer](/docs/capabilities/flags/data-transfer).

## Related Resources

<CardGroup cols={2}>
  <Card title="Manage API Clients" href="/docs/capabilities/flags/manage-clients">
    Manage API clients and credentials
  </Card>

  <Card title="Materialized Segments" href="/docs/capabilities/segments/materialized-segments">
    Bloom filters and local segment resolution
  </Card>

  <Card title="Data Transfer" href="/docs/capabilities/flags/data-transfer">
    Understand data flow options
  </Card>

  <Card title="SDKs Reference" href="/docs/reference/sdks/overview">
    SDK configuration options
  </Card>
</CardGroup>
