Skip to main content
All code examples for the ClickHouse API can be found here. For connection configuration, see Configuration. For supported data types and Go type mappings, see Data Types.

Connecting

The following example, which returns the server version, demonstrates connecting to ClickHouse - assuming ClickHouse isn’t secured and accessible with the default user. Note we use the default native port to connect.
Full Example For all subsequent examples, unless explicitly shown, we assume the use of the ClickHouse conn variable has been created and is available.

Execution

Arbitrary statements can be executed via the Exec method. This is useful for DDL and simple statements. It shouldn’t be used for larger inserts or query iterations.
Full Example Note the ability to pass a Context to the query. This can be used to pass specific query level settings - see Using Context.

Batch insert

To insert a large number of rows, the client provides batch semantics. This requires the preparation of a batch to which rows can be appended. This is finally sent via the Send() method. Batches are held in memory until Send is executed. It is recommended to call Close on the batch to prevent leaking connections. This can be done via the defer keyword after preparing the batch. This will clean up the connection if Send never gets called. Note that this will result in 0 row inserts showing up in the query log if no rows were appended.
Full Example Recommendations for ClickHouse apply here. Batches shouldn’t be shared across go-routines - construct a separate batch per routine. From the above example, note the need for variable types to align with the column type when appending rows. While the mapping is usually obvious, this interface tries to be flexible, and types will be converted provided no precision loss is incurred. For example, the following demonstrates inserting a string into a datetime64.
Full Example For a full summary of supported go types for each column type, see Type Conversions.

Ephemeral columns

Ephemeral columns are write-only columns that exist only during insertion — they are not stored and cannot be selected. They are useful for computing derived column values at insert time.
Full Example

Querying rows

You can either query for a single row using the QueryRow method or obtain a cursor for iteration over a result set via Query. While the former accepts a destination for the data to be serialized into, the latter requires the call to Scan on each row.
Full Example
Full Example Note in both cases, we’re required to pass a pointer to the variables we wish to serialize the respective column values into. These must be passed in the order specified in the SELECT statement - by default, the order of column declaration will be used in the event of a SELECT * as shown above. Similar to insertion, the Scan method requires the target variables to be of an appropriate type. This again aims to be flexible, with types converted where possible, provided no precision loss is possible, e.g., the above example shows a UUID column being read into a string variable. For a full list of supported go types for each Column type, see Type Conversions. Finally, note the ability to pass a Context to the Query and QueryRow methods. This can be used for query level settings - see Using Context for further details.

Async insert

Asynchronous inserts are supported through the Async method. This allows the user to specify whether the client should wait for the server to complete the insert or respond once the data has been received. This effectively controls the parameter wait_for_async_insert.
Full Example

Columnar insert

Inserts can be inserted in column format. This can provide performance benefits if the data is already orientated in this structure by avoiding the need to pivot to rows.
Full Example

Using structs

For users, Golang structs provide a logical representation of a row of data in ClickHouse. To assist with this, the native interface provides several convenient functions.

Select with serialize

The Select method allows a set of response rows to be marshaled into a slice of structs with a single invocation.
Full Example

Scan struct

ScanStruct allows the marshaling of a single Row from a query into a struct.
Full Example

Append struct

AppendStruct allows a struct to be appended to an existing batch and interpreted as a complete row. This requires the columns of the struct to align in both name and type with the table. While all columns must have an equivalent struct field, some struct fields may not have an equivalent column representation. These will simply be ignored.
Full Example

Parameter binding

The client supports parameter binding for the Exec, Query, and QueryRow methods. As shown in the example below, this is supported using named, numbered, and positional parameters. We provide examples of these below.
Full Example

Special cases

By default, slices will be unfolded into a comma-separated list of values if passed as a parameter to a query. If you require a set of values to be injected with wrapping [ ], ArraySet should be used. If groups/tuples are required, with wrapping ( ) e.g., for use with IN operators, you can use a GroupSet. This is particularly useful for cases where multiple groups are required, as shown in the example below. Finally, DateTime64 fields require precision in order to ensure parameters are rendered appropriately. The precision level for the field is unknown by the client, however, so the user must provide it. To facilitate this, we provide the DateNamed parameter.
Full Example

Using context

Go contexts provide a means of passing deadlines, cancellation signals, and other request-scoped values across API boundaries. All methods on a connection accept a context as their first variable. While previous examples used context.Background(), you can use this capability to pass settings and deadlines and to cancel queries. Passing a context created withDeadline allows execution time limits to be placed on queries. Note this is an absolute time and expiry will only release the connection and send a cancel signal to ClickHouse. WithCancel can alternatively be used to cancel a query explicitly. The helpers clickhouse.WithQueryID and clickhouse.WithQuotaKey allow a query id and quota key to be specified. Query ids can be useful for tracking queries in logs and for cancellation purposes. A quota key can be used to impose limits on ClickHouse usage based on a unique key value - see Quotas Management for further details. You can also use the context to ensure a setting is only applied for a specific query - rather than for the entire connection, as shown in Connection Settings. Finally, you can control the size of the block buffer via the clickhouse.WithBlockSize. This overrides the connection level setting BlockBufferSize and controls the maximum number of blocks that are decoded and held in memory at any time. Larger values potentially mean more parallelization at the expense of memory. Examples of the above are shown below.
Full Example

Progress, profile and log information

Progress, Profile, and Log information can be requested on queries. Progress information will report statistics on the number of rows and bytes that have been read and processed in ClickHouse. Conversely, Profile information provides a summary of data returned to the client, including totals of bytes (uncompressed), rows, and blocks. Finally, log information provides statistics on threads, e.g., memory usage and data speed. Obtaining this information requires the user to use Context, to which the user can pass call-back functions.
Full Example

Dynamic scanning

You may need to read tables for which they don’t know the schema or type of the fields being returned. This is common in cases where ad-hoc data analysis is performed or generic tooling is written. To achieve this, column-type information is available on query responses. This can be used with Go reflection to create runtime instances of correctly typed variables which can be passed to Scan.
Full Example

External tables

External tables allow the client to send data to ClickHouse, with a SELECT query. This data is put in a temporary table and can be used in the query itself for evaluation. To send external data to the client with a query, the user must build an external table via ext.NewTable before passing this via the context.
Full Example

Open telemetry

ClickHouse supports trace context propagation on both TCP and HTTP transports. When using TCP, the client serializes the span into the native binary protocol. Use clickhouse.WithSpan to attach a span to a query via the context.
HTTP transport limitationWhile ClickHouse server accepts the standard traceparent / tracestate HTTP headers, the clickhouse-go HTTP transport does not currently send them — WithSpan has no effect over HTTP. As a workaround, you can set the header manually via HttpHeaders in the connection options.
Full Example Full details on exploiting tracing can be found under OpenTelemetry support.
Last modified on July 2, 2026