Selecting an insert strategy

## Choose an interface—HTTP or native[​](#choose-an-interface "Direct link to Choose an interface—HTTP or native")

### Native[​](#choose-an-interface-native "Direct link to Native")

ClickHouse offers two main interfaces for data ingestion: the **native interface** and the **HTTP interface**—each with trade-offs between performance and flexibility. The native interface, used by [clickhouse-client](/docs/interfaces/cli) and select language clients like Go and C++, is purpose-built for performance. It always transmits data in ClickHouse's highly efficient Native format, supports block-wise compression with LZ4 or ZSTD, and minimizes server-side processing by offloading work such as parsing and format conversion to the client.

It even enables client-side computation of MATERIALIZED and DEFAULT column values, allowing the server to skip these steps entirely. This makes the native interface ideal for high-throughput ingestion scenarios where efficiency is critical.

### HTTP[​](#choose-an-interface-http "Direct link to HTTP")

Unlike many traditional databases, ClickHouse also supports an HTTP interface. **This, by contrast, prioritizes compatibility and flexibility.** It allows data to be sent in [any supported format](/docs/integrations/data-formats)—including JSON, CSV, Parquet, and others—and is widely supported across most ClickHouse clients, including Python, Java, JavaScript, and Rust.

This is often preferable to ClickHouse's native protocol as it allows traffic to be easily switched with load balancers. We expect small differences in insert performance with the native protocol, which incurs a little less overhead.

However, it lacks the native protocol's deeper integration and can't perform client-side optimizations like materialized value computation or automatic conversion to Native format. While HTTP inserts can still be compressed using standard HTTP headers (e.g. `Content-Encoding: lz4`), the compression is applied to the entire payload rather than individual data blocks. This interface is often preferred in environments where protocol simplicity, load balancing, or broad format compatibility is more important than raw performance.

For a more detailed description of these interfaces see [here](/docs/interfaces/overview).

- [Synchronous inserts by default](#synchronous-inserts-by-default)
  - [Batch inserts if synchronous](#batch-inserts-if-synchronous)- [Ensure idempotent retries](#ensure-idempotent-retries)- [Choose the right insert target](#choose-the-right-insert-target)- [Choose the right format](#choose-the-right-format)- [Use compression](#use-compression)- [Pre-sort if low cost](#pre-sort-if-low-cost)- [Asynchronous inserts](#asynchronous-inserts)
    - [Choosing a return mode](#choosing-a-return-mode)- [Adaptive async inserts](#adaptive-async-inserts)- [Error handling](#error-handling)- [Deduplication and reliability](#deduplication-and-reliability)- [Enabling asynchronous inserts](#enabling-asynchronous-inserts)- [Flushing buffers on shutdown](#flushing-buffers-on-shutdown)- [Comparison with buffer tables](#comparison-with-buffer-tables)- [Choose an interface—HTTP or native](#choose-an-interface)
      - [Native](#choose-an-interface-native)- [HTTP](#choose-an-interface-http)

Was this page helpful?