> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-revert-104359-revert-104251-parquet-single.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Replica-aware routing

> Route related requests to the same ClickHouse Cloud replica for temporary tables, sessions, cache reuse, and read-after-write consistency

export const EnterprisePlanFeatureBadge = ({feature = 'This feature', support = false, linking_verb_are = false}) => {
  return <div className="enterprisePlanFeatureContainer">
            <div className="enterprisePlanFeatureBadge">
                Enterprise plan feature
            </div>
            <div>
                <p>{feature} {linking_verb_are ? 'are' : 'is'} available in the Enterprise plan. {support ? `Contact support to enable this feature.` : 'To upgrade, visit the plans page in the cloud console.'}</p>
            </div>
        </div>;
};

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Beta</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Beta feature</span>
        </a>;
};

<BetaBadge />

<EnterprisePlanFeatureBadge feature="Replica-aware routing" />

Replica-aware routing (also known as sticky sessions, sticky routing, or session affinity) routes related requests to the same ClickHouse replica. Use it when you need [temporary tables](/reference/statements/create/table/temporary-table) or [named session state](/concepts/features/interfaces/http#using-clickhouse-sessions-in-the-http-protocol) to stay reachable across queries, when you want related queries to reuse the same replica's local caches, or when you need [read-after-write consistency](#read-after-write-consistency) across a write and its follow-up reads.

It's best-effort and doesn't guarantee isolation. The proxy maps each routing value to one replica. The mapping remains stable while the number of replicas remains unchanged; scaling the service can map the value to a different replica.

Replica-aware routing is available over both interfaces:

* Over [HTTP/HTTPS](#http-based-routing), using the `X-ClickHouse-Replica-Tag` header.
* Over the [native protocol](#native-protocol-routing), using a TLS Server Name Indication (SNI) override.

Both are enabled separately and use the same consistent hashing behind the proxy.

<h2 id="prerequisites">
  Prerequisites
</h2>

* Your service needs **2 or more replicas**. On a single-replica service, there's nothing to pin to.
* An **Enterprise** tier service.
* Supported on standard ClickHouse Cloud services. [BYOC](/products/cloud/guides/infrastructure/deployment-options/byoc/overview) isn't supported yet.

<h2 id="configuring-replica-aware-routing">
  Configuring replica-aware routing
</h2>

Enterprise customers enable replica-aware routing from the service settings page in the ClickHouse Cloud console. Open your service, go to **Settings**, and turn on the toggle for the interface you want:

* One toggle enables HTTP-based routing on the `X-ClickHouse-Replica-Tag` header.
* A separate toggle enables native-protocol routing on the SNI override.

Enable either or both. No restart is required, and it can take under a minute to take effect.

The toggles are rolling out across Enterprise tier plans. If they aren't on your service yet, open a [support](https://clickhouse.com/support/program) ticket with your service ID to have the feature turned on earlier.

<h2 id="http-based-routing">
  HTTP-based routing
</h2>

To pin a workload to a replica, send an `X-ClickHouse-Replica-Tag` header on the [HTTPS interface](/concepts/features/interfaces/http). The proxy uses consistent hashing on the header value, so requests sharing it go to the same replica while the number of replicas remains unchanged. A different value hashes independently and may land on the same or a different replica, but you don't choose *which* replica a value maps to.

Use your existing service hostname. No special sticky hostnames or DNS changes are required. The header value can be any string you choose, such as an application name, user ID, or workload label. Requests without the header keep normal load balancing.

Set the `X-ClickHouse-Replica-Tag` header on each request:

```bash theme={null}
echo 'SELECT hostName()' | curl \
  -H 'X-ClickHouse-Replica-Tag: my-workload-1' \
  -H 'X-ClickHouse-User: default' \
  -H 'X-ClickHouse-Key: <password>' \
  'https://<host>:8443/' -d @-
```

For clickhouse-go (v2), set `Protocol: clickhouse.HTTP` and pass the header with the [`HttpHeaders` connection option](/integrations/language-clients/go/configuration#connection-settings).

<Info>
  `X-ClickHouse-Replica-Tag` provides replica affinity without creating a ClickHouse HTTP session. Concurrent requests can reuse the same tag without encountering `SESSION_IS_LOCKED`.
</Info>

<h2 id="native-protocol-routing">
  Native-protocol routing
</h2>

Over the [native protocol](/interfaces/tcp), pass the routing value as a TLS server name of the form `<routing-value>.sticky.<host>`. Connect to your regular service hostname as usual. [ClickHouse Client](/interfaces/client) takes the routing value through `--tls-sni-override`:

```bash theme={null}
clickhouse client \
  --host <host> \
  --secure \
  --tls-sni-override my-workload-1.sticky.<host> \
  --query 'SELECT hostName()'
```

`--host` is your regular service hostname, `--secure` turns on TLS, and `--tls-sni-override` carries the routing value. TLS is required. No extra certificate or DNS entry is needed.

<h2 id="read-after-write-consistency">
  Read-after-write consistency
</h2>

On a multi-replica service, a write on one replica may not be visible on the others until replication catches up. Send your write with a routing value, then reuse that same value on follow-up reads. The proxy routes both to the same replica, so you read your own write even while other replicas are still behind. This pattern works for workloads that write and then immediately read back the same data, such as interactive applications or ETL jobs that validate inserts before moving on.

It also helps after a schema change that hasn't yet replicated, since reusing the routing value keeps inserts on a replica that already has the new schema.

Over HTTP, reuse the header value:

```bash theme={null}
# Write, tagged with a routing value
echo "INSERT INTO events VALUES (now(), 'signup')" | curl \
  -H 'X-ClickHouse-Replica-Tag: my-workload-1' \
  -H 'X-ClickHouse-User: default' \
  -H 'X-ClickHouse-Key: <password>' \
  'https://<host>:8443/' -d @-

# Read it back on the same replica, using the same value
echo 'SELECT count() FROM events' | curl \
  -H 'X-ClickHouse-Replica-Tag: my-workload-1' \
  -H 'X-ClickHouse-User: default' \
  -H 'X-ClickHouse-Key: <password>' \
  'https://<host>:8443/' -d @-
```

Over the native protocol, reuse the SNI override:

```bash theme={null}
# Write with a routing value
clickhouse client \
  --host <host> \
  --secure \
  --tls-sni-override my-workload-1.sticky.<host> \
  --query "INSERT INTO events VALUES (now(), 'signup')"

# Read it back on the same replica, using the same value
clickhouse client \
  --host <host> \
  --secure \
  --tls-sni-override my-workload-1.sticky.<host> \
  --query 'SELECT count() FROM events'
```

For broader guarantees across all replicas, you can also set [`select_sequential_consistency`](/reference/settings/session-settings#select_sequential_consistency) to `1` on ClickHouse Cloud.

<h2 id="check-which-replica">
  Check which replica you hit
</h2>

Run one of the `SELECT hostName()` examples again with the same routing value. You should get the same hostname while the number of replicas remains unchanged. A different routing value may map to a different replica.

<h2 id="limitations-of-replica-aware-routing">
  Limitations of replica-aware routing
</h2>

<h3 id="replica-aware-routing-does-not-guarantee-isolation">
  Stickiness changes when the replica count changes
</h3>

Scaling out or in changes the routing hash ring. Requests sharing the same routing value may then land on a different replica. If you rely on temporary tables or session-level settings, be ready to recreate them after a remap. `SELECT hostName()` always tells you which replica you're on.

<h3 id="not-workload-isolation">
  Replica-aware routing isn't workload isolation
</h3>

Sticky routing only controls *which* replica handles a request. That replica may still serve other traffic. For dedicated compute, use [compute-compute separation](/products/cloud/features/infrastructure/warehouses).

<h3 id="private-networking">
  Private networking
</h3>

Both HTTP-based and native-protocol routing work with [private networking](/products/cloud/guides/security/connectivity/private-networking) on your normal service hostname. No extra DNS entries are required.

<h3 id="native-protocol-routing-requires-tls">
  Native-protocol routing requires TLS
</h3>

Native-protocol routing needs TLS, so pass `--secure`. An unencrypted native connection keeps normal load balancing.

<h2 id="troubleshooting">
  Troubleshooting
</h2>

**Queries still land on different replicas with the same routing value**

* Confirm the toggle for the interface you're using is enabled on the service settings page. The HTTP and native methods are enabled separately.
* Over HTTP, confirm that every request includes the `X-ClickHouse-Replica-Tag` header, and that every request uses exactly the same value.
* Over the native protocol, confirm that `--secure` is set and that `--tls-sni-override` has the form `<routing-value>.sticky.<host>`.
* Wait briefly after enablement. It can take under a minute to take effect.
* Check whether the number of replicas recently changed; remapping is expected after scaling. Use `SELECT hostName()` to discover the new mapping.

**Certificate errors over the native protocol**

* Confirm `--host` is your regular service hostname, and that the routing value is passed through `--tls-sni-override` rather than `--host`.
