Releases: ClickHouse/clickhouse-connect
Release list
v1.8.0rc2
clickhouse-connect v1.8.0rc2
This is the second release candidate for testing the optional Rust codec. RC2 updates the driver onto the 1.7.2 stable release, incorporating all of its bug fixes. The Rust codec itself is unchanged from RC1.
Please test this release with your workloads and report any issues. Install it with a pinned version:
pip install "clickhouse-connect[rust]==1.8.0rc2"
What's Changed Since v1.8.0rc1
Query and transport fixes
- Queries ending in a semicolon now keep client-appended
FORMATclauses inside the statement, including trailing whitespace and comments. Insert detection now follows SQL token rules. Fixes
#903. - The async client now preserves explicit
proxy_pathvalues exactly. Fixes #963. - The synchronous client now normalizes an empty request path to
/when using a forwarding HTTP proxy. Fixes #951. - Server-side query parameter names can now contain
$where ClickHouse permits it, while preserving the driver's raw binary binding convention. Fixes [#936](https://github.com/ClickHouse/ - ClickHouse type literals containing percent signs now compile safely alongside bound parameters. Fixes #966.
- Generic
literal_binds, DDL string clauses, comments, and Alembic comment operations now use ClickHouse-compatible backslash escaping. Fixes [#975](https://github.com/ClickHouse/clickhouse-
connect/issues/975). union(),intersect(), andexcept_()now emit explicitDISTINCToperations, preserving SQLAlchemy semantics. Use their_all()counterparts when duplicate-preserving behavior is
intended. Fixes #973.- Applicable
Select.with_hint()table hints now emitSAWarninginstead of being silently ignored. Fixes #974.
Rust codec testing
The optional Rust codec remains experimental. The default python codec is unchanged.
To enable Rust with Python fallback:
client = clickhouse_connect.get_client(
host="...",
native_codec="rust",
)For testing, native_codec="rust_strict" raises on unsupported paths instead of falling back.
Installation
For this release candidate:
pip install "clickhouse-connect[rust]==1.8.0rc2"
For the latest stable release:
pip install clickhouse-connect
v1.7.2
clickhouse-connect v1.7.2
This patch release fixes SQLAlchemy reflection and SQL generation, query formatting, server-side parameter names, and HTTP proxy path handling.
What's Changed
Bug Fixes
- SQLAlchemy inspectors bound to an
Enginenow supportget_columns()andreflect_table()on SQLAlchemy 2.x. Reflection also honorsinclude_columnsandexclude_columns. Closes #967. - Queries ending with a semicolon, whitespace, or trailing comment now place client-appended
FORMATclauses correctly. Insert detection also follows SQL token rules. Closes #903. - The async client now preserves explicit
proxy_pathvalues without adding extra slashes. Closes #963. - The synchronous client now sends a normalized
/request path through forwarding HTTP proxies when noproxy_pathis configured. Closes #951. - Server-side query placeholders now recognize
$in valid parameter names while preserving raw binary binding and ambiguity checks. Closes #936. - SQLAlchemy ClickHouse types now implement the public literal processor contract for
TypeDecoratorandwith_variant(). Closes #965. - SQLAlchemy literals containing percent signs now compile safely alongside bound parameters and in server-side parameter mode. Closes #966.
- SQLAlchemy now applies ClickHouse backslash escaping to generic literal strings, defaults, aliases, TTL clauses, comments, and Alembic comment operations. Custom pre-escaping workarounds should be removed. Closes #975.
- SQLAlchemy
union(),intersect(), andexcept_()now emit explicitDISTINCToperations. Use the corresponding_all()methods when duplicate-preserving behavior is required. Closes #973. - SQLAlchemy
Select.with_hint()now emitsSAWarningwhen an applicable table hint would otherwise be ignored. Generated SQL remains unchanged. Closes #974.
Full Changelog: v1.7.1...v1.7.2
Installation
pip install clickhouse-connectv1.8.0rc1
clickhouse-connect v1.8.0rc1
This is a release candidate for testing the new optional Rust codec. Please try it and report any issues. Install it with a pinned version:
pip install "clickhouse-connect[rust]==1.8.0rc1"
Highlights
Experimental Rust native codec
This release adds an experimental native_codec client option that selects the codec used for FORMAT Native query decode and insert encode.
pythonis the default and uses the existing codec, so nothing changes unless you opt in.rustprefers the compiled Rust codec and falls back to the Python codec for unsupported options and types (which should be (hopefully) rare).rust_strictraises instead of falling back and is the recommended mode for testing.
The compiled codec is published as the separate clickhouse-connect-core wheel, installed automatically by the [rust] extra. Wheels cover CPython 3.10 through 3.14 on Linux x86_64 and aarch64 for glibc 2.28 and newer plus musl, macOS, and Windows x64 and arm64. Results and dtypes match the Python codec, and the Arrow methods are unaffected.
To enable it on a client:
client = clickhouse_connect.get_client(host=..., native_codec="rust")This is early access for benchmarking and testing. See the rust-codec documentation page for details.
Also included
Everything in the 1.7.0 and 1.7.1 stable releases.
Installation
For this release candidate: pip install "clickhouse-connect[rust]==1.8.0rc1"
For the latest stable release: pip install clickhouse-connect
v1.7.1
clickhouse-connect v1.7.1
This is a patch release with two SQLAlchemy compatibility fixes.
What's Changed
Bug Fixes
- SQLAlchemy 2.1 compatibility: Identifier quoting forwarded the deprecated
forceargument toIdentifierPreparer.quote, which SQLAlchemy 2.1 removed, causing any dialect use to raiseTypeErroron 2.1.0b3. The parent call now passes only the identifier. The optionalforceparameter remains available on the ClickHouse preparer for direct callers. Closes #954. - SQLAlchemy 1.4 compatibility: Column DDL using the
clickhouse_materialized,clickhouse_alias, orclickhouse_ttloptions raisedAttributeErroron SQLAlchemy 1.4 because it called a rendering helper that only exists in 2.0. The helper is now implemented locally. This appears to have been broken since 1.1.0.
Full Changelog: v1.7.0...v1.7.1
Installation
pip install clickhouse-connect
v1.7.0
clickhouse-connect 1.7.0
clickhouse-connect 1.7.0 adds SQLAlchemy support for JSON subcolumns and materialized CTEs, introduces more control over error messages and naive datetime inserts, and fixes issues across parameter binding, streaming, JSON decoding, DB-API, and SQLAlchemy.
Highlights
Features and improvements
- SQLAlchemy JSON columns now support storage-backed subcolumn access through
column["segment"],column.subcolumn(...), and the typedjson_subcolumn(...)helper. #899 - SQLAlchemy statements can create materialized CTEs through
.cte(..., materialized=True)andcc_sqlalchemy.cte(...). This requires ClickHouse 26.3 or later withenable_materialized_cteand the analyzer enabled. #900 show_clickhouse_errors="scrub"preserves useful server error details while removing the server URL and version trailer. Transport and streaming errors follow the same setting. Invalid values now raiseProgrammingError. #344- The new
naive_datetime_insertsetting controls whether naive Python datetime values use the client host timezone or the column and server timezone. The default remains"local"for compatibility. #938
Bug fixes
- SQLAlchemy and DB-API now handle percent signs in identifiers correctly, including
%2EJSON key encodings. datetime.timeanddatetime.timedeltaquery parameters now bind correctly forTimeandTime64, including nested, negative, extended-duration, timezone-aware, and nanosecond values. SQLAlchemy inserts, comparisons, andliteral_bindsnow support these values too. #919- The DB-API module now provides the standard
Binary,Date,Time,Timestamp, and ticks-based constructors. This also fixes SQLAlchemyLargeBinaryinserts. #919 - Fractional
DateTime64values before the Unix epoch now serialize to the correct second. #938 - Nested compound types containing enum values with escaped quotes now parse correctly. #878
- Nested
Nonevalues in arrays, tuples, and map-formatted maps now render as SQLNULL. #879 - Empty bytes inserted into non-nullable
FixedStringcolumns are now padded correctly. #880 - Settings unavailable through
system.settings, including custom role settings, are now forwarded to ClickHouse for validation. #530 - SQLAlchemy reflection and metadata queries continue returning string identifiers when the global
Stringformat is configured as bytes. #920 - Removing SQL block comments no longer joins adjacent query tokens or causes incorrect client-side
LIMIThandling. #928 - Native streaming now detects complete mid-stream ClickHouse exception blocks across transport chunk boundaries. #915
- DB-API
Cursor.descriptionnow reports accurate top-level nullability and handles empty-result metadata probes more safely. #902, #907, #909 - Compound and temporal values stored in JSON shared data now decode to Python values instead of raw bytes. #897
- Async streaming cleanup now runs on the event-loop thread, preserving the original
StreamFailureErrorwhen TLS queries fail mid-stream.
Compatibility notes
- Runtime compatibility branches for unsupported ClickHouse versions older than 25.8 have been removed. ClickHouse 25.8 is now the supported baseline.
datetime.timeanddatetime.timedeltaparameters are now quoted by the driver. Remove manual quotes around existing%(name)splaceholders. #919- Naive datetime query parameters now represent wall time in the target timezone. Set
common.set_setting("naive_datetime_binding", "legacy")to restore the previous host-timezone conversion behavior. #938
Installation
pip install clickhouse-connectv1.6.0
What's Changed
clickhouse-connect 1.6.0 adds an experimental in-process chDB backend, resolves several sync/async client parity bugs, and replaces the zstandard dependency with the standard library/a backport. Internally, the sync and async HTTP clients were unified onto a shared backend core, which is what enables the chDB backend and fixes the async issues below.
Features
- Added an experimental in-process chDB backend.
get_client(interface='chdb')or achdb://DSN returns a standard client that runs queries against an embedded chDB engine instead of a ClickHouse server, supporting the full query, insert, streaming, and Arrow client surface. Use thepathargument or achdb:///on/disk/pathDSN for a persistent database. Requires thechdbpackage, installable withpip install clickhouse-connect[chdb]. chDB allows one engine per process, has no async client, and does not support external data. (#872)
Bug Fixes
AsyncClientinitialization no longer overwrites user-supplied session settings with generated defaults which no matches the sync client. (#872)- An
AsyncClientcreated with both client certificates and an access token now sends the mutual TLS authentication headers and theAuthorization: Bearerheader together which now also matches the sync client. (#872) - Dict-valued settings such as
additional_table_filtersno longer crash withDB::Exception: Cannot parse quoted stringwhen passed throughquery()'ssettingsparameter. Closes #501.
Improvements
- Async clients now emit URL query parameters in the same order as the sync client on every request. (#872)
- Client creation no longer fails when the
client_protocol_versioncapability probe errors on the sync client; it now falls back gracefully and logs at debug level, matching the async client. - Replaced the
zstandarddependency with the stdlibcompression.zstdmodule (Python 3.14+) andbackports.zstd(Python 3.10-3.13), giving a single consistent call surface across all supported Python versions. zstd compression remains fully supported on all standard Python installs. Closes #577.
Under the hood
- The sync and async HTTP clients were refactored onto a shared, internal pluggable-backend core (
asyncclient.pyshrank by roughly 1,200 lines of duplicated logic). This is an internal change with no public API surface, but it's the basis for the chDB backend and the sync/async parity fixes above. (#872)
Installation
pip install clickhouse-connectv1.5.0
clickhouse-connect 1.5.0
This is a feature release focused on the SQLAlchemy and Alembic integration, alongside two important correctness fixes on the core driver. Alembic gains first-class support for ClickHouse-specific DDL, SQLAlchemy gains per-query settings and typed ClickHouse query chainables, and Variant columns gain a new lossless read format. On the driver side, this release fixes a data-corruption bug when decoding large varints on the compiled path and a QBit corruption bug for dimensions greater than 8.
Highlights
Features
- Alembic support for ClickHouse-specific DDL. New runtime Alembic operations cover skip indexes, projections, table settings, materialized views, and dictionaries, including plural add/drop helpers for indexes and projections. The plural helpers emit a single comma-joined
ALTER TABLEso replicated deployments avoid theCode: 517 CANNOT_ASSIGN_ALTERrace. Helpers render valid SQL in offline--sqlmode. #839 - Per-query ClickHouse settings in SQLAlchemy.
execution_options(settings={...})now forwards per-query settings through the dialect and DB-API cursor for Core andtext()statements,execute,executemany, and the bulk-insert path. Settings set at the connection or engine level compose with per-statement settings, and per-statement values take precedence, so a connection-level default applies to implicit ORM queries such asselectinloadand lazy loads. #838, #846 - Chainable JOIN modifiers. A new
Select.ch_join()lets ClickHouse JOIN modifiers be written in normal SQLAlchemy chaining style. It takes the strictness modifiers ALL, ANY, ASOF, SEMI, and ANTI, the GLOBAL distribution modifier, plus USING and CROSS as keyword arguments. The existingch_join()factory is unchanged. #827 - Typed ClickHouse select.
cc_sqlalchemy.select()returns aClickHouseSelectexposingch_join,final,sample,array_join,prewhere, andlimit_byas typed methods, so static type checkers accept them without suppressions. The standardsqlalchemy.select()path is unchanged. #837 typedread format forVariantcolumns. When two members of aVariantshare a Python type, such asVariant(Float32, Float64), reading with thetypedformat wraps each value as aTypedVariantcarrying both the value and itstype_name, and these feed straight back into inserts. Enable per query withquery_formats={'Variant': 'typed'}or globally withset_read_format('Variant', 'typed'). The defaultnativeformat is unchanged. #825
Bug Fixes
- Fixed corruption of
QBitcolumns with a dimension greater than 8 on native inserts and reads. Data written by earlier clients was stored incorrectly and should be re-inserted. See the upgrade note below. #866 - The compiled Cython response buffer now decodes LEB128 varint values of 2^31 and larger correctly. Each 7-bit group was shifted in signed 32-bit arithmetic before being widened, so any varint of 2^31 or more was truncated or corrupted. This affected string and nullable string column lengths and every other varint read on the compiled path. The pure Python reader was already correct. #828
command()now returns an empty string for a read that produces an empty result set, instead of a truthyQuerySummarythat madeif result:misleading. #865- DB API
Cursor.executemanyno longer falls off the bulk-insert fast path when an INSERT names backtick-quoted dotted columns such as the wire form ofNestedsub-columns.unescape_identifiernow removes backtick quoting from compound identifiers correctly, which previously degraded the operation to slow per-row execution and could raiseProgrammingErrorwith dict rows and pyformat placeholders. #820
SQLAlchemy Bug Fixes
- MergeTree engine key clauses
order_by,partition_by,primary_key,sample_by, andttlnow accept arbitrary SQL expressions such ascol.desc(),func.cityHash64(a, b),tuple_(...), and interval TTL expressions, in scalar and list forms. Expression engines round-trip throughrepr()for Alembic autogeneration. #845 has_database()now usesEXISTS DATABASEinstead of queryingsystem.databases. On servers from 25.10 through 26.4,system.databasesomitted DataLakeCatalog and other remote databases by default, sohas_database()reportedFalsefor databases that actually exist. #849MATERIALIZEDandALIAScolumns now keep theircomment,codec, andttloptions in generated DDL, and column clauses are emitted in the order ClickHouse requires,COMMENTthenCODECthenTTL. This also fixes a pre-existing case where a column combining a codec with a comment produced invalid SQL. #856ClickHouseSelectnow keeps its typed ClickHouse chainables after column-shape methods such asadd_columns(),with_only_columns(),column(), andreduce_columns().cc_sqlalchemy.select()also works on SQLAlchemy 1.4. #844- Wrapping a ClickHouse type in a SQLAlchemy
TypeDecoratorno longer raisesTypeError: result_processor() takes 0 positional arguments but 2 were givenwhen reading results. #847 - The Alembic
op.rename_tablenow emitsRENAME TABLE old TO newinstead of theALTER TABLE old RENAME TO newform ClickHouse rejects. Standard SQLAlchemy indexes are filtered from ClickHouse autogenerate output, andColumn(index=True),Index(...),op.create_index, andop.drop_indexraise a clear Alembic error before partially applying DDL. Useop.add_clickhouse_indexandop.drop_clickhouse_indexfor data-skipping indexes. #839 - Fixed several Alembic ClickHouse DDL helper edge cases: raw SQL fragments containing
:nameare no longer parsed as bind parameters, dictionary comments escape backslashes correctly, explicit schemas are honored for legal dotted table names,CREATE MATERIALIZED VIEWno longer accepts a misleadingclickhouse_settingssuffix, and custom ClickHouse operation objects render through autogenerate instead of raisingValueError. #839
Upgrade notes
QBitdimension greater than 8. Values written by earlier clients were stored incorrectly on the wire. After upgrading, re-insert any affectedQBitdata. #866command()return value. A read that returns no rows now yields an empty string rather than a truthyQuerySummary. Code that relied oncommand()for a read always being truthy should check the returned value explicitly. #865
Installation
pip install clickhouse-connect
Full Changelog: v1.4.2...v1.5.0
v1.4.2
clickhouse-connect 1.4.2
Patch release with a single bug fix on top of 1.4.1. No new features and no breaking changes.
Bug Fixes
- Async inserts and queries with an in-memory body larger than 1 MiB no longer emit an aiohttp ResourceWarning about sending a large body directly with raw bytes. Bytes and string request bodies are now wrapped in an io.BytesIO so aiohttp writes them in chunks. This affects the async Arrow insert methods and any large raw insert or query body. Closes #850.
Full Changelog: v1.4.1...v1.4.2
v1.4.1
clickhouse-connect 1.4.1
This is a patch release with two bug fixes. One restores correct Alembic autogenerate output for non-ClickHouse dialects after the ClickHouse integration is imported. The other completes the return-type annotations on the async client so callers running mypy in strict mode no longer get errors.
What's Changed
Bug Fixes
- SQLAlchemy: importing the ClickHouse Alembic integration no longer changes Alembic autogenerate output for other database dialects. The ClickHouse renderers for
CreateTableOp,AddColumnOp, andDropTableOpwere registered as process-wide replacements with no dialect guard, because Alembic renderers have no per-dialect dispatch. Any non-ClickHouse autogenerate run in the same process then used the ClickHouse renderers, which dropped thenullableargument from columns whose nullability was not set explicitly and injectedcc_sqlalchemyimports. The renderers now fall back to Alembic's built-in rendering for non-ClickHouse dialects. Closes #832. - Several public
AsyncClientmethods now carry the return-type annotations their syncClientcounterparts already had.close,close_connections,query_np,query_df,query_arrow,set_client_setting, andset_access_tokenwere missing them, so downstream projects running mypy with--disallow-untyped-callsgotno-untyped-callerrors on calls likeawait client.close()once the package began shippingpy.typedin 1.4.0. The async client surface is now fully annotated. This is a type-only change with no runtime effect. Closes #831.
Installation
pip install clickhouse-connect
v1.4.0
clickhouse-connect 1.4.0
This is a minor release. It adds experimental free-threading support, ships type information for downstream type checkers, and fixes bugs across the core client, the DB-API cursor, and the SQLAlchemy dialect.
Highlights
Features and improvements
- Free-threading compatibility. The Cython extension modules now declare free-threading support, so importing clickhouse-connect on a free-threaded build such as Python 3.14t no longer silently re-enables the GIL. Free-threading support remains experimental. The CI suite now runs the full test matrix on 3.14t as a non-blocking job.
- PEP 561 type information. The package now ships a
py.typedmarker so downstream type checkers can use its annotations. #692 Noneforportanddatabase.create_client,create_async_client,connect(), and the DB-APIConnectionconstructor now acceptNoneto request the driver's defaults, in addition to omitting them. The internal sentinel values are still accepted, so this is backward compatible. #801QueryResult.query_idnow returns an empty string instead ofNonewhen the server reported no query id. This matchesQuerySummaryand keeps the property consistently typed asstr.
Bug fixes
QueryResult.first_itemandQueryResult.first_rownow returnNonefor an empty result set instead of raisingIndexError. #824Cursor.executemanynow resetsrowcountand reports the number of inserted rows after a bulk insert, and appends the insert summary tocursor.summary. Passing a generator asseq_of_parametersno longer raisesTypeError. The bulk-insert optimization is skipped for non-indexable iterables and falls through to the row-by-row path as PEP 249 requires.- A connection failure partway through reading a query result is no longer silently treated as a complete result. A mid-stream read failure now raises
StreamFailureError, carrying the server-side error message when ClickHouse reported one. #802 Client.insert_arrowandAsyncClient.insert_arrowno longer drop thetransport_settingsargument. It was passed positionally into thecompressionparameter, so transport settings were ignored. It is now forwarded correctly.commandnow raisesProgrammingErrorwhen binary parameter binds are combined with command data or external data, instead of placing binary content into the URL query string. This applies to both the sync and async clients.- Importing clickhouse-connect no longer emits a
DeprecationWarningfor the array'u'type code. This also lets projects that run with-W errorimport the package. #815 - The SQLAlchemy
NullableandLowCardinalityDDL helpers are now functions that return a concreteChSqlaType, soArray(LowCardinality(String))no longer raises a spurious mypy error. Runtime behavior is unchanged. #819
Compatibility
Client.insert,AsyncClient.insert, andraw_insertnow requirecolumn_namesto be aSequencerather than a bareIterable. A one-shot iterator such as a generator already failed at runtime because the column names are measured and iterated more than once, so the type hint now matches the real requirement.
Upgrade notes
- Building from source now requires Cython 3.1 or later.
- If you pass
column_namesas a generator or other one-shot iterator, switch to aSequencesuch as a list or tuple. This path already failed at runtime.
Installation
pip install clickhouse-connect