Java client library to communicate with a DB server through its protocols. The current implementation only supports the HTTP interface.
The library provides its own API to send requests to a server. The library also provides tools to work with different binary data formats (RowBinary* & Native*).
Authentication by an access token or Bearer token (such as a JWT) requires setting the token by calling Authentication by a SSL Client Certificate require setting username, enabling SSL Authentication, setting a client certificate and a client key by calling
will result in the following Application can set own http header ⚠️ When options are set via Important: When options are set via To configure per operation, set the header on All subsequent requests on the ParametersParametersParametersParametersParametersParametersParametersParametersIntegration ApproachesApplications can integrate observability using two primary patterns:V2 Insert TSV formatted data.
Setup
- Maven Central (project web page): https://mvnrepository.com/artifact/com.clickhouse/client-v2
- Nightly builds (repository link): https://central.sonatype.com/repository/maven-snapshots/
- Maven
- Gradle (Kotlin)
- Gradle
Initialization
The Client object is initialized bycom.clickhouse.client.api.Client.Builder#build(). Each client has its own context and no objects are shared between them.
The Builder has configuration methods for convenient setup.Example:showLineNumbers
Client is AutoCloseable and should be closed when not needed anymore.Authentication
Authentication is configured per client at the initialization phase. There are three authentication methods supported: by password, by access token, by SSL Client Certificate.Authentication by a password requires setting user name password by callingsetUsername(String) and setPassword(String):showLineNumbers
useBearerTokenAuth(String) (or setAccessToken(String) for raw access tokens):showLineNumbers
setUsername(String), useSSLAuthentication(boolean), setClientCertificate(String) and setClientKey(String) accordingly:showLineNumbers
SSL Authentication may be hard to troubleshoot on production because many errors from SSL libraries provide not enough information. For example, if client certificate and key don’t match then server will terminate connection immediately (in case of HTTP it will be connection initiation stage where no HTTP requests are send so no response is sent).Please use tools like openssl to verify certificates and keys:
- check key integrity:
openssl rsa -in [key-file.key] -check -noout - check client certificate has matching CN for a user:
- get CN from an user certificate -
openssl x509 -noout -subject -in [user.cert] - verify same value is set in database
select name, auth_type, auth_params from system.users where auth_type = 'ssl_certificate'(query will outputauth_paramswith something like{"common_names":["some_user"]})
- get CN from an user certificate -
Connection Pooling
TheClient uses Apache HttpClient 5 with an internal HTTP connection pool. Each operation borrows a connection from the pool, sends the request, streams the response, and returns the connection to the pool.Key connection pool settings on Client.Builder:Recommended Connection Pool Configuration
showLineNumbers
Configuration
All settings are defined by instance methods (a.k.a configuration methods) that make the scope and context of each value clear. Major configuration parameters are defined in one scope (client or operation) and don’t override each other.Configuration is defined during client creation. Seecom.clickhouse.client.api.Client.Builder.Client Configuration
- Connection & Endpoints
- Authentication
- Timeouts & Retry
- Socket Options
- Compression
- SSL/Security
- Proxy
- HTTP & Headers
- Server Settings
- Timezone
- Advanced
Client Identification
There are two fields in a query log that identify application originated a request:client_name and http_user_agent. Native TCP protocol uses
client_name to identify application. HTTP protocol uses http_user_agent to identify application. Client builder has method setClientName correct values
for both protocols.
The field http_user_agent is set according to User-Agent header common format: application-name[/version] [(operating-system; architecture; ...)].
This set of values is repeated for each layer: application, client library, http client library. What is set by setClientName method comes first in the list.For example:showLineNumbers
http_user_agent value:User-Agent to identify itself. But part clickhouse-java-v2/0.9.6-SNAPSHOT will be appended to the end of the header.Operation Identification
Query log has another two fieldsquery_id and log_comment that can be used to identify an operation and add additional information to the query log.query_id is a unique identifier of an operation. It can be set by application by calling setQueryId method of the QuerySettings class.showLineNumbers
log_comment is a comment that can be added to the query log. It can be set by application by calling logComment method of the QuerySettings class.showLineNumbers
Server Settings
Server side settings can be set on the client level once while creation (seeserverSetting method of the Builder) and on operation level (see serverSetting for operation settings class).showLineNumbers
setOption method (either the Client.Builder or operation settings class) then server settings name should be prefixed with clickhouse_setting_. The com.clickhouse.client.api.ClientConfigProperties#serverSetting() may be handy in this case.Custom HTTP Headers
Custom HTTP headers can be set for all operations (client level) or a single one (operation level). Operation settings override client-level headers with the same name.showLineNumbers
setOption (on Client.Builder or an operation settings class), prefix the header name with http_header_. ClientConfigProperties.httpHeader(String) builds that key.
As header name is simple String key it should be in one letter case otherwise duplicate values will result undefined behavior, ClientConfigProperties.httpHeader(String) fixes this problem.showLineNumbers
ClickHouse Cloud Features
Features that apply when connecting to ClickHouse Cloud.Replica-aware Routing (CLOUD)
ClickHouse Cloud can pin related HTTP requests to the same replica. Send theX-ClickHouse-Replica-Tag header so a Cloud proxy routes every request that shares the tag to one replica. Use this for session-scoped objects such as temporary tables, replica-local cache reuse, or read-after-write consistency.
Read more: https://clickhouse.com/docs/products/cloud/features/infrastructure/replica-aware-routing.What to set: HTTP header X-ClickHouse-Replica-Tag (com.clickhouse.client.api.http.ClickHouseHttpProto.HEADER_REPLICA_TAG). Use the same tag value for all requests that should stay on one replica.showLineNumbers
QuerySettings, InsertSettings, or CommandSettings instead of the client builder.JWT Authentication (CLOUD)
JWT Authentication allows authenticating users with JSON Web Tokens (JWTs) in ClickHouse Cloud. Instead of pre-existing database users, ClickHouse dynamically creates ephemeral users derived from claims embedded in each token.Initial Configuration
To configure initial JWT authentication on the client, useuseBearerTokenAuth(token) (this automatically adds Bearer_ prefix.
(see HTTP interface docs ) when building the Client instance:showLineNumbers
useBearerTokenAuth(token) automatically prepends the Bearer prefix to the Authorization HTTP header.Updating Token at Runtime
Because JWTs are short-lived and ephemeral users exist only for the token’s lifetime, new JWT tokens should be set before the current token expires so no operations fail.You can update the bearer token on an existingClient instance at runtime without recreating the client:showLineNumbers
Client instance will use the updated JWT token.Common Definitions
ClickHouseFormat
Enum of supported formats. It includes all formats that ClickHouse supports.raw- user should transcode raw datafull- the client can transcode data by itself and accepts a raw data stream-- operation not supported by ClickHouse for this format
Insert API
insert(String tableName, InputStream data, ClickHouseFormat format)
Accepts data as anInputStream of bytes in the specified format. It is expected that data is encoded in the format.SignaturestableName - a target table name.data - an input stream of an encoded data.format - a format in which the data is encoded.settings - request settings.Return valueFuture of InsertResponse type - result of the operation and additional information like server side metrics.ExamplesshowLineNumbers
insert(String tableName, List<?> data, InsertSettings settings)
Sends a write request to database. The list of objects is converted into an efficient format and then is sent to a server. The class of the list items should be registered up-front usingregister(Class, TableSchema) method.SignaturestableName - name of the target table.data - collection DTO (Data Transfer Object) objects.settings - request settings.Return valueFuture of InsertResponse type - the result of the operation and additional information like server side metrics.ExamplesshowLineNumbers
InsertSettings
Configuration options for insert operations.Configuration methodsInsertResponse
Response object that holds result of insert operation. It is only available if the client got response from a server.This object should be closed as soon as possible to release a connection because the connection can’t be re-used until all data of previous response is fully read.
Query API
Format SelectionClient provides transparent access to the response stream from server. User is free to choose any ClickHouse format in request and read data viaInputStream
from QueryResponse object.
Format can be requested via:QuerySettings#setFormat()this will set format header in a request.- In
FORMATclause in query itself. - Server settings
default_format(/reference/settings/session-settings/default#default_format)
- Client <
0.11.0& ClickHouse <26.8-FORMATclause has priority over request format header. - Client >
0.11.0& ClickHouse >26.8- request header has priority overFORMATclause.- Client sets header when no format is specified in
QuerySettings- this doesn’t allow to override format in query.
- Client sets header when no format is specified in
- Client starting
0.11.0- sets defaultformatvalue on client level and not on operation level. This allows existing code work without changes and new code to useFORMATclause by settingsformaton client tonull.
query(String sqlQuery)
SendssqlQuery as is. Response format is set by query settings. QueryResponse will hold a reference to the response stream that should be consumed by a reader for the supportig format.SignaturessqlQuery - a single SQL statement. The Query is sent as is to a server.settings - request settings.Return valueFuture of QueryResponse type - a result dataset and additional information like server side metrics. The Response object should be closed after consuming the dataset.Examplesquery(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)
SendssqlQuery as is. Additionally will send query parameters so the server can compile the SQL expression.SignaturessqlQuery - sql expression with placeholders {}.queryParams - map of variables to complete the sql expression on server.settings - request settings.Return valueFuture of QueryResponse type - a result dataset and additional information like server side metrics. The Response object should be closed after consuming the dataset.ExamplesshowLineNumbers
queryAll(String sqlQuery)
Queries a data inRowBinaryWithNamesAndTypes format. Returns the result as a collection. Read performance is the same as with the reader but more memory is required to hold the whole dataset.SignaturessqlQuery - sql expression to query data from a server.Return valueComplete dataset represented by a list of GenericRecord objects that provide access in row style for the result data.ExamplesshowLineNumbers
QuerySettings
Configuration options for query operations.Configuration methodsQueryResponse
Response object that holds result of query execution. It is only available if the client got a response from a server.This object should be closed as soon as possible to release a connection because the connection can’t be re-used until all data of previous response is fully read.
Examples
- Example code is available in repo
- Reference Spring Service implementation
Common API
getTableSchema(String table)
Fetches table schema for thetable.Signaturestable - table name for which schema data should be fetched.database - database where the target table is defined.Return valueReturns a TableSchema object with list of table columns.getTableSchemaFromQuery(String sql)
Fetches schema from a SQL statement.Signaturessql - “SELECT” SQL statement which schema should be returned.Return valueReturns a TableSchema object with columns matching the sql expression.TableSchema
register(Class<?> clazz, TableSchema schema)
Compiles serialization and deserialization layer for the Java Class to use for writing/reading data withschema. The method will create a serializer and deserializer for the pair getter/setter and corresponding column.
Column match is found by extracting its name from a method name. For example, getFirstName will be for the column first_name or firstname.Signaturesclazz - Class representing the POJO used to read/write data.schema - Data schema to use for matching with POJO properties.ExamplesshowLineNumbers
Usage Examples
Complete examples code is stored in the repo in a ‘example` folder:- client-v2 - main set of examples.
- demo-service - example of how to use the client in a Spring Boot application.
- demo-kotlin-service - example of how to use the client in Ktor (Kotlin) application.
Reading Data
There are two common ways to read data:query()method that returns low-levelQueryResponseobject that containsInputStreamwith data. Usually combined withClickHouseBinaryFormatReaderfor streaming reads but can be used with any other custom reader implementation.QueryResponsealso provides access to the result set metadata and metrics.queryAll()method and usingGenericRecordfor convenient row access. In this case the whole result set is loaded into memory.queryRecords()method that returnscom.clickhouse.client.api.query.Records- an iterator forGenericRecordobjects. This method uses streaming approach (no data is loaded into memory) and utilisesGenericRecordto access data.
Reading Arrays
ClickHouseBinaryFormatReader MethodsgetList(...)- reads anyArray(...)asList<T>. Good default for flexible typed reads. Supports nested arrays.getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)- best for 1D arrays of primitive-compatible values.getStringArray(...)- forArray(String)(and enum values represented as names).getObjectArray(...)- generic option for anyArray(...)element type, including nested arrays. Use to read arrays with nullable values and nested arrays.
GenericRecord MethodsgetList(...)- reads anyArray(...)asList<T>. Good default for flexible typed reads. Supports nested arrays.getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)- best for 1D arrays of primitive-compatible values.getStringArray(...)- forArray(String)(and enum values represented as names).getObjectArray(...)- generic option for anyArray(...)element type, including nested arrays. Use to read arrays with nullable values and nested arrays.
Observability & Monitoring
The ClickHouse Java Client (V2) provides built-in observability features designed around OpenTelemetry semantic conventions and Micrometer metrics. The client enables monitoring operational durations, throughput, retries, server execution statistics, connection pool status, and distributed tracing spans.For a complete production-style Spring Boot application demonstrating Client V2 configuration, connection pooling, trace context propagation across@Async boundaries, and full telemetry integration, see the examples/demo-spring-service module in this repository.Client Builder Observability API
TheClient.Builder exposes three primary methods to configure observability and metrics collection:setMetricsRecorder(MetricsRecorder recorder): Registers a metrics recorder for exporting operational metrics (durations, counts, retries, errors). When not explicitly set, defaults toDefaultMetricsRecorder.NOOP.setSpanRecorder(SpanRecorder recorder): Registers a span recorder for distributed tracing (operation spans and transport request spans). When not explicitly set, defaults toDefaultSpanRecorder.NOOP.registerClientMetrics(Object registry, String groupName): Binds Apache HttpClient connection pool metrics (such as available and leased connections, pending requests, and connection creation time) to a MicrometerMeterRegistry.
OpenTelemetrySpanRecorder and MicrometerMetricsRecorder classes are provided as part of the client-v2 package. However, they require the OpenTelemetry API (io.opentelemetry:opentelemetry-api) and Micrometer (io.micrometer:micrometer-core) libraries to be present on the application’s classpath at runtime. The main client artifact does not bundle these third-party dependencies nor pull them in transitively. Applications using OpenTelemetry tracing or Micrometer metrics must explicitly declare these dependencies in their project build configuration (pom.xml or build.gradle).Builder Configuration Example- OpenTelemetry Agent & Global Autoconfiguration:
- For applications using the OpenTelemetry Java Agent or global SDK autoconfiguration, instantiate
OpenTelemetrySpanRecorderandMicrometerMetricsRecorderusing their default no-argument constructors. - The default constructors automatically bind to
GlobalOpenTelemetry.get()and Micrometer’sMetrics.globalRegistry.
- For applications using the OpenTelemetry Java Agent or global SDK autoconfiguration, instantiate
- Explicit Client-Level Integration:
- Pass explicitly created
OpenTelemetry,Tracer, or MicrometerMeterRegistryinstances directly into the recorder constructors. - Ideal when managing multiple isolated clients or multi-tenant services with independent telemetry sinks.
- Pass explicitly created
Metrics Reported
Operational Metrics
Metrics exported viaMetricsRecorder follow the OpenTelemetry semantic conventions for database client metrics (MetricName and MetricAttribute):Metric Attributes / Tags
Meters created byMicrometerMetricsRecorder carry low-cardinality tags (MetricAttribute):Connection Pool Metrics
When callingregisterClientMetrics(meterRegistry, "groupName"), HTTP connection pool gauges are registered with Micrometer:httpcomponents.httpclient.pool.total.max: Configured maximum allowed persistent connections.httpcomponents.httpclient.pool.total.connections(tagged withstate="available"orstate="leased"): Active connections in the pool.httpcomponents.httpclient.pool.total.pending: Number of connection requests awaiting a free connection.httpcomponents.httpclient.pool.route.max.default: Configured default maximum connections per route.httpcomponents.httpclient.connect.time: Running average connection establishment time.
Response Metrics API
In addition to metrics recorders, detailed execution statistics are accessible directly on response objects (QueryResponse, InsertResponse) via OperationMetrics:Spans Reported
Tracing in Client V2 produces two types of spans arranged in a parent-child hierarchy:- Operation Span: Represents a high-level client operation (
QUERY <database>orINSERT <database>.<table_name>). Started under the current thread’s trace context (Context.current()) so that database operations join the caller’s active trace span. - Transport Request Span: Represents an individual HTTP transport request attempt (
POST). Created as a child of the corresponding operation span. Each retry attempt creates a new transport request span under the operation span.
Span Attributes
Spans are populated with standard OpenTelemetry attributes (SpanAttribute):Context Propagation Across Asynchronous Boundaries: Because Client V2 inherits
Context.current(), operations started on threads with an active trace span automatically join the trace. When delegating tasks across thread pools (e.g., Spring @Async or custom ExecutorService), propagate the OpenTelemetry context explicitly:Developing Custom Recorders
Applications with custom observability backends can implement custom recorders by extendingDefaultMetricsRecorder (for metrics) or DefaultSpanRecorder (for tracing).DefaultMetricsRecorder: Base implementation ofMetricsRecorder. Override specific callbacks likerecordQuerySuccessorrecordQueryFailure. UseMetricsSupport.DEFAULTto derive standard metric names (MetricName), units, and attribute maps (MetricAttribute).DefaultSpanRecorder: Base implementation ofSpanRecorder. Override span creation callbacks likestartQuerySpan,startInsertSpan, orstartRequestSpan. UseSpanSupport.DEFAULTto calculate standard OpenTelemetry span names and attributes (SpanAttribute).
com.clickhouse.client.api.observability.otel.OpenTelemetrySpanRecorder(OpenTelemetry tracing integration)com.clickhouse.client.api.observability.micrometer.MicrometerMetricsRecorder(Micrometer metrics integration)
Migration Guide
Old client (V1) was usingcom.clickhouse.client.ClickHouseClient#builder as start point. The new client (V2) uses similar pattern with com.clickhouse.client.api.Client.Builder. Main
differences are:- no service loader is used to grab implementation. The
com.clickhouse.client.api.Clientis facade class for all kinds of implementation in the future. - a fewer sources of configuration: one is provided to the builder and one is with operation settings (
QuerySettings,InsertSettings). Previous version had configuration per node and was loading env. variables in some cases.
Configuration Parameters Match
There are 3 enum classes related to configuration in V1:com.clickhouse.client.config.ClickHouseDefaults- configuration parameters that supposed to be set in most use cases. LikeUSERandPASSWORD.com.clickhouse.client.config.ClickHouseClientOption- configuration parameters specific for the client. LikeHEALTH_CHECK_INTERVAL.com.clickhouse.client.http.config.ClickHouseHttpOption- configuration parameters specific for HTTP interface. LikeRECEIVE_QUERY_PROGRESS.
com.clickhouse.client.config.ClickHouseDefaults#ASYNC and
com.clickhouse.client.config.ClickHouseClientOption#ASYNC). The new V2 client uses com.clickhouse.client.api.Client.Builder as single dictionary of all possible client configuration options.There is
com.clickhouse.client.api.ClientConfigProperties where all configuration parameter names are listed.Table below shows what old options are supported in the new client and their new meaning.Legend: ✔ = supported, ✗ = dropped- Connection & Auth
- SSL & Security
- Socket Options
- Compression
- Proxy
- Timeouts & Retry
- Timezone
- Buffers & Performance
- Threading & Async
- HTTP & Headers
- Format & Query
- Node Discovery & Load Balancing
- Miscellaneous
General Differences
- Client V2 uses less proprietary classes to increase portability. For example, V2 works with any implementation of
java.io.InputStreamfor writing data to a server. - Client V2
asyncsettings isoffby default. It means no extra threads and more application control over client. This setting should beofffor majority of use cases. Enablingasyncwill create a separate thread for a request. It only make sense when using application controlled executor (seecom.clickhouse.client.api.Client.Builder#setSharedOperationExecutor)
Writing Data
- use any implementation of
java.io.InputStream. V1com.clickhouse.data.ClickHouseInputStreamis supported but NOT recommended. - once end of input stream is detected it handled accordingly. Previously output stream of a request should be closed.
- there is a single method to call. No need to create an additional request object.
- request body stream is closed automatically when all data is copied.
- new low-level API is available
com.clickhouse.client.api.Client#insert(java.lang.String, java.util.List<java.lang.String>, com.clickhouse.client.api.DataStreamWriter, com.clickhouse.data.ClickHouseFormat, com.clickhouse.client.api.insert.InsertSettings).com.clickhouse.client.api.DataStreamWriteris designed to implement custom data writing logic. For instance, reading data from a queue.
Reading Data
- Data is read in
RowBinaryWithNamesAndTypesformat by default. Currently only this format is supported when data binding is required. - Data can be read as a collection of records using
List<GenericRecord> com.clickhouse.client.api.Client#queryAll(java.lang.String)method. It will read data to a memory and release connection. No need for extra handling.GenericRecordgives access to data, implements some conversions.