ClickHouse Rust client

[Edit this page](https://github.com/ClickHouse/clickhouse-docs/blob/main/docs/integrations/language-clients/rust.md)

The official Rust client for connecting to ClickHouse, originally developed by [Paul Loyd](https://github.com/loyd). The client source code is available in the [GitHub repository](https://github.com/ClickHouse/clickhouse-rs).

## Overview[​](#overview "Direct link to Overview")

- Uses `serde` for encoding/decoding rows.
- Supports `serde` attributes: `skip_serializing`, `skip_deserializing`, `rename`.
- Uses [`RowBinary`](/docs/interfaces/formats/RowBinary) format over the HTTP transport.
  - There are plans to switch to [`Native`](/docs/interfaces/formats/Native) over TCP.
- Supports TLS (via `native-tls` and `rustls-tls` features).
- Supports compression and decompression (LZ4).
- Provides APIs for selecting or inserting data, executing DDLs, and client-side batching.
- Provides convenient mocks for unit testing.

## Installation[​](#installation "Direct link to Installation")

To use the crate, add the following to your `Cargo.toml`:

```
[dependencies]
clickhouse = "0.12.2"

[dev-dependencies]
clickhouse = { version = "0.12.2", features = ["test-util"] }
```

See also: [crates.io page](https://crates.io/crates/clickhouse).

## Cargo features[​](#cargo-features "Direct link to Cargo features")

- `lz4` (enabled by default) — enables `Compression::Lz4` and `Compression::Lz4Hc(_)` variants. If enabled, `Compression::Lz4` is used by default for all queries except for `WATCH`.
- `native-tls` — supports urls with the `HTTPS` schema via `hyper-tls`, which links against OpenSSL.
- `rustls-tls` — supports urls with the `HTTPS` schema via `hyper-rustls`, which doesn't link against OpenSSL.
- `inserter` — enables `client.inserter()`.
- `test-util` — adds mocks. See [the example](https://github.com/ClickHouse/clickhouse-rs/tree/main/examples/mock.rs). Use it only in `dev-dependencies`.
- `watch` — enables `client.watch` functionality. See the corresponding section for details.
- `uuid` — adds `serde::uuid` to work with [uuid](https://docs.rs/uuid) crate.
- `time` — adds `serde::time` to work with [time](https://docs.rs/time) crate.

References

When connecting to ClickHouse via an `HTTPS` url, either the `native-tls` or `rustls-tls` feature should be enabled.
If both are enabled, the `rustls-tls` feature will take precedence.

## ClickHouse versions compatibility[​](#clickhouse-versions-compatibility "Direct link to ClickHouse versions compatibility")

The client is compatible with the LTS or newer versions of ClickHouse, as well as ClickHouse Cloud.

ClickHouse server older than v22.6 handles RowBinary [incorrectly in some rare cases](https://github.com/ClickHouse/ClickHouse/issues/37420).
You could use v0.11+ and enable `wa-37420` feature to solve this problem. Note: this feature shouldn't be used with newer ClickHouse versions.

## Examples[​](#examples "Direct link to Examples")

We aim to cover various scenarios of client usage with the [examples](https://github.com/ClickHouse/clickhouse-rs/blob/main/examples) in the client repository. The overview is available in the [examples README](https://github.com/ClickHouse/clickhouse-rs/blob/main/examples/README.md#overview).

If something is unclear or missing from the examples or from the following documentation, feel free to [contact us](/docs/integrations/rust#contact-us).

## Usage[​](#usage "Direct link to Usage")

Note

[ch2rs](https://github.com/ClickHouse/ch2rs) crate is useful to generate a row type from ClickHouse.

### Creating a client instance[​](#creating-a-client-instance "Direct link to Creating a client instance")

Tip

Reuse created clients or clone them in order to reuse the underlying hyper connection pool.

```
use clickhouse::Client;

let client = Client::default()
    // should include both protocol and port
    .with_url("http://localhost:8123")
    .with_user("name")
    .with_password("123")
    .with_database("test");
```

### HTTPS or ClickHouse Cloud connection[​](#https-or-clickhouse-cloud-connection "Direct link to HTTPS or ClickHouse Cloud connection")

HTTPS works with either `rustls-tls` or `native-tls` cargo features.

Then, create client as usual. In this example, the environment variables are used to store the connection details:

References

The URL should include both protocol and port, e.g. `https://instance.clickhouse.cloud:8443`.

```
fn read_env_var(key: &str) -> String {
    env::var(key).unwrap_or_else(|_| panic!("{key} env variable should be set"))
}

let client = Client::default()
    .with_url(read_env_var("CLICKHOUSE_URL"))
    .with_user(read_env_var("CLICKHOUSE_USER"))
    .with_password(read_env_var("CLICKHOUSE_PASSWORD"));
```

See also:

- [HTTPS with ClickHouse Cloud example](https://github.com/ClickHouse/clickhouse-rs/blob/main/examples/clickhouse_cloud.rs) in the client repo. This should be applicable to on-premise HTTPS connections as well.

### Selecting rows[​](#selecting-rows "Direct link to Selecting rows")

```
use serde::Deserialize;
use clickhouse::Row;
use clickhouse::sql::Identifier;

#[derive(Row, Deserialize)]
struct MyRow<'a> {
    no: u32,
    name: &'a str,
}

let table_name = "some";
let mut cursor = client
    .query("SELECT ?fields FROM ? WHERE no BETWEEN ? AND ?")
    .bind(Identifier(table_name))
    .bind(500)
    .bind(504)
    .fetch::<MyRow<'_>>()?;

while let Some(row) = cursor.next().await? { .. }
```

- Placeholder `?fields` is replaced with `no, name` (fields of `Row`).
- Placeholder `?` is replaced with values in following `bind()` calls.
- Convenient `fetch_one::<Row>()` and `fetch_all::<Row>()` methods can be used to get a first row or all rows, correspondingly.
- `sql::Identifier` can be used to bind table names.

NB: as the entire response is streamed, cursors can return an error even after producing some rows. If this happens in your use case, you could try `query(...).with_option("wait_end_of_query", "1")` in order to enable response buffering on the server-side. [More details](/docs/interfaces/http#response-buffering). The `buffer_size` option can be useful, too.

Note

Use `wait_end_of_query` with caution when selecting rows, as it can will to higher memory consumption on the server side and will likely decrease the overall performance.

### Inserting rows[​](#inserting-rows "Direct link to Inserting rows")

```
use serde::Serialize;
use clickhouse::Row;

#[derive(Row, Serialize)]
struct MyRow {
    no: u32,
    name: String,
}

let mut insert = client.insert("some")?;
insert.write(&MyRow { no: 0, name: "foo".into() }).await?;
insert.write(&MyRow { no: 1, name: "bar".into() }).await?;
insert.end().await?;
```

- If `end()` isn't called, the `INSERT` is aborted.
- Rows are being sent progressively as a stream to spread the network load.
- ClickHouse inserts batches atomically only if all rows fit in the same partition and their number is less [`max_insert_block_size`](https://clickhouse.tech/docs/operations/settings/settings/#settings-max_insert_block_size).

### Async insert (server-side batching)[​](#async-insert-server-side-batching "Direct link to Async insert (server-side batching)")

You could use [ClickHouse asynchronous inserts](/docs/optimize/asynchronous-inserts) to avoid client-side batching of the incoming data. This can be done by simply providing the `async_insert` option to the `insert` method (or even to the `Client` instance itself, so that it will affect all the `insert` calls).

```
let client = Client::default()
    .with_url("http://localhost:8123")
    .with_option("async_insert", "1")
    .with_option("wait_for_async_insert", "0");
```

See also:

- [Async insert example](https://github.com/ClickHouse/clickhouse-rs/blob/main/examples/async_insert.rs) in the client repo.

### Inserter feature (client-side batching)[​](#inserter-feature-client-side-batching "Direct link to Inserter feature (client-side batching)")

Requires the `inserter` cargo feature.