Scope note: This comparison reflects the current documentation and product boundaries checked for this article. ClickHouse, PostgreSQL, Debezium, sink connectors, and managed CDC services change over time. Treat capability statements as product- and deployment-specific, and rerun the compatibility checks before production rollout. Performance and cost claims without a reproducible benchmark are not presented as universal results.
If PostgreSQL is your system of record and ClickHouse is where analytics happen, CDC is the bridge between the two. But the hard part is not extracting an UPDATE from PostgreSQL. The hard part is making sure the right state arrives in ClickHouse, remains queryable, survives a restart, and continues to behave when the source schema changes.

That is why this comparison ( Debezium vs. Estuary Flow vs. MaterializedPostgreSQL) is not really about three competing connectors. It is about three different places to put operational complexity:
- Debezium puts most of the control, and most of the moving parts in your CDC and streaming platform.
- Estuary Flow puts more of the capture, delivery, and materialization workflow inside a managed service.
- MaterializedPostgreSQL keeps the path close to PostgreSQL and ClickHouse, but its fit depends heavily on the current ClickHouse deployment, version, schema, and workload.
Key Takeaways
- Debezium is the control-first choice when Kafka or a comparable event platform already exists and multiple consumers need the same change stream.
- Estuary Flow is the managed-operations choice when the team wants less self-managed streaming infrastructureābut still needs to verify cost, recovery, schema, and delivery boundaries.
- MaterializedPostgreSQL is the native-coupling choice when the current ClickHouse path is supported for the deployment and the workload fits its logical-replication and schema boundaries.
- The real decision is not āwhich connector is fastest?ā It is āwhich architecture can prove correct, query-visible data and recover cleanly under our workload?ā
The short answer ( ClickHouse CDC: Debezium vs. Estuary Flow vs. MaterializedPostgreSQL)
There is no honest universal winner. The right decision changes with the number of tables, the ratio of updates to inserts, the need for multiple downstream consumers, the destination model, the amount of schema change, and the recovery guarantees your team actually needs.
| If your situation looks like this | Start by evaluating | Why | Validate before committing |
|---|---|---|---|
| A few tables, no Kafka, small platform team | Estuary Flow or the supported native path | Avoids introducing a large streaming platform for a narrow use case | Managed-service cost, recovery, deletes, and schema behavior |
| Kafka already runs in production | Debezium with Kafka Connect and a ClickHouse sink | Reuses existing topics, governance, monitoring, and replay patterns | Sink correctness, topic design, converters, and operational ownership |
| ClickHouse Cloud is the destination | ClickPipes or another currently supported managed route | Cloud support and networking boundaries change the choice | Current support, source connectivity, pricing, and schema handling |
| Self-managed ClickHouse with a simple topology | MaterializedPostgreSQL | Keeps replication close to the source and destination | Engine status, PostgreSQL requirements, DDL, failover, and target semantics |
| Many consumers need the same change stream | Debezium/Kafka or managed fan-out | A reusable stream may be more valuable than a point-to-point pipe | Retention, replay, ordering, schema governance, and cost |
Heavy UPDATE and DELETE traffic | Benchmark all viable options | ClickHouse row-state modeling becomes a first-order concern | Duplicate density, merge behavior, delete convergence, and query correctness |
š„ Download: ClickHouse CDC Production Readiness Checklist
Planning your PostgreSQL-to-ClickHouse deployment? Download our complete, battle-tested Production Readiness Checklist covering replication slots, WAL failover, DDL evolution matrices, and data convergence.
⬠Direct Download (Free) Instant download · No signup or email requiredWhat PostgreSQL-to-ClickHouse CDC actually does
PostgreSQLās current logical replication documentation describes logical replication as a publish-and-subscribe model. It normally begins with a snapshot of the source data and then sends committed changes continuously; replication identity, usually a primary key helps identify the affected row.

CDC tools build on that source-side mechanism. A typical pipeline has five stages:
- Capture: Read changes from PostgreSQLās write-ahead log through logical decoding.
- State: Remember where the reader is in the source stream.
- Transport: Buffer, route, or transform the events.
- Materialization: Write the events into ClickHouse tables.
- Convergence: Make sure the table represents the intended current state when merges, deletes, retries, or out-of-order events occur.
The last stage is where many āworkingā demos become production problems. A green source connector only proves that changes were captured. It does not prove that the ClickHouse sink accepted them, that the destination table used the right key, or that a query returns the correct row after asynchronous merging.
For a deeper treatment of the failure boundary between PostgreSQL slots, connector offsets, retries, duplicate-safe sinks, and recovery runbooks, see this Postgres CDC production reliability guide. It complements this comparison by focusing on what happens after the first successful change is captured.
CDC latency is not one number
A serious comparison should separate:
- PostgreSQL commit to capture.
- Capture to transport.
- Transport to sink.
- Sink write to ClickHouse merge.
- PostgreSQL commit to query-visible state.
A vendor can report excellent capture latency while the analytical table still has merge delay, backpressure, or a target-model problem. For the reader, the useful metric is usually commit-to-query-visible freshness, not the fastest stage in the pipeline.
Debezium: the control-first option
Debezium is best understood as a family of source connectors and deployment patterns, not as a mandatory āPostgreSQL to Kafkaā product bundle. In its common Kafka Connect architecture, the PostgreSQL connector reads logical changes, performs a consistent snapshot, and emits row-level change events to Kafka topics, as described in Debeziumās PostgreSQL connector documentation.
The usual architecture looks like this:
That architecture is powerful because each layer has a clear role. Kafka can buffer events and support multiple consumers. Kafka Connect provides a runtime for source and sink connectors. Debezium exposes source changes in a structured event model. The ClickHouse sink controls how those records are converted and inserted.
The trade-off is equally clear: you own the boundaries between those layers.

What Debezium does well
Debeziumās PostgreSQL documentation covers logical decoding, snapshots, replica identity, WAL consumption, event records, data types, monitoring, and failure behavior. The current documentation also covers incremental, ad hoc, blocking, and configuration-based snapshot patterns.
That makes Debezium attractive when you need:
- A reusable event backbone for more than one destination.
- Detailed control over source capture and event shape.
- Kafka retention and replay as part of the operating model.
- Multiple deployment choices.
- A platform that can evolve beyond one PostgreSQL-to-ClickHouse link.
Debezium also offers deployment options outside the standard Kafka Connect setup. Debeziumās architecture documentation also describes Debezium Server, which can send events to several messaging infrastructures, and Debezium Engine, which can be embedded in a custom Java application.
Where Debezium becomes expensive
The connector is not the whole system. Your team may need to operate PostgreSQL replication settings, slots, snapshots, Kafka brokers, Connect workers, topic retention, converters, sink configuration, ClickHouse target tables, schema governance, monitoring, and recovery procedures.
That does not make Debezium a bad choice. It makes it a poor default for a team that only needs a few tables and has no reason to operate Kafka. It also means that a āDebezium versus managed CDCā comparison should compare operational ownership, not only connector features.
A common failure boundary is the sink. Kafka can contain the expected records while ClickHouse shows missing rows because of a topic-to-table mismatch, converter issue, rejected batch, incorrect target schema, or an unsuitable table model. The community research for this topic surfaced exactly that kind of report: a viewer saw Kafka changes but no visible rows in the target table. That is a troubleshooting signal, not evidence of a general Debezium defect.
Which ClickHouse sink should you use with Debezium?
Debezium captures the source change. The sink decides how that change becomes a ClickHouse insert, how schemas are interpreted, and whether the target table can represent updates and deletes. Treating āDebezium to ClickHouseā as a complete product name hides the most important implementation choice.
| Sink option | What it is | Payload-to-column behavior | When to consider it | Main caveat |
|---|---|---|---|---|
| Official ClickHouse Kafka Connect Sink | A ClickHouse-maintained Kafka Connect sink that consumes Kafka topics and writes to existing ClickHouse tables. | Kafka Connect converters determine whether the sink receives JSON, String, Avro, or Protobuf-style data; the target schema must match the records. | A strong default when your team already runs Kafka Connect and wants the ClickHouse-maintained path. | Verify connector/ClickHouse versions, converters, topic-to-table mapping, retries, DLQ, and the configured exactlyOnce mode. |
| Altinity ClickHouse Sink Connector | An open-source sink with Kafka and lightweight deployment models; its repository documents PostgreSQL/MySQL CDC via Debezium, ReplacingMergeTree targets, recovery, schema handling, and type mapping. | Connector mapping and mutable-data handling shape the ClickHouse table; inspect the documentation for the release you deploy. | Useful when you want an alternative deployment model or PostgreSQL-oriented replication workflow. | Confirm release support, target-engine assumptions, source features, and commercial/support boundaries. |
| ClickHouse Kafka table engine | A ClickHouse table engine that consumes Kafka directly; it is not a Debezium-specific sink. | kafka_format controls parsing, and a materialized view commonly transforms the stream into a target table. | Useful when ClickHouse should consume Kafka directly and the team is prepared to own consumer and view logic. | Consumer groups, offsets, parsing errors, retries, transformations, and target correctness become your responsibility. |
The official ClickHouse Kafka Connect Sink documentation says the connector writes to existing tables and requires converter choices that match the records. It documents topic-to-table mapping, retry behavior, dead-letter handling, and an exactlyOnce configuration path. That does not make the final analytical table automatically correct: a transport or connector guarantee is different from deduplicating rows, applying tombstones, and producing correct query results.
The ClickHouse Kafka table-engine documentation describes a stream consumer and recommends materialized views for continuously transforming Kafka messages into tables. A raw Debezium envelope usually needs deliberate extraction or transformation before the destination model can use it.
Sink rule: Choose the sink only after you have answered three questions: what shape does the CDC event have, what shape should the ClickHouse row have, and where will deduplication and deletion semantics be enforced?
Estuary Flow: the managed-operations option
Estuary Flow approaches the problem as a managed capture-and-materialization service. In Estuaryās ClickHouse destination documentation, the vendor describes a workflow in which collections are delivered through ClickHouseās native protocol, tables and schemas can be managed automatically, and users can choose between standard merge behavior and delta updates.

The page also states support for exactly-once delivery and soft or hard deletes.
The practical appeal is simple:
You do not have to assemble every middle-layer component yourself. That can shorten the path from source configuration to a working pipeline, particularly when the goal is a small number of destinations or when the team does not want Kafka to become another platform responsibility.
What Estuary Flow does well
Estuaryās current product material emphasizes:
- Managed real-time and batch connectors.
- Direct ClickHouse materialization.
- Automatic table and schema management.
- Merge or delta-update modes.
- Soft and hard delete support.
- Fan-out from captured data to multiple destinations.
Its Postgres-to-ClickHouse guide also uses a useful editorial sequence: why the systems are paired, why batch ETL falls short, how the pipeline works, how schema evolution and deletes are handled, how bulk load affects performance, and which questions readers ask most often.
That structure is valuable even when you are not buying the product. It reflects the questions a production team should ask of any managed CDC service.
If you are implementing the managed path, this PostgreSQL-to-ClickHouse CDC implementation guide with Estuary Flow provides a hands-on companion for source prerequisites, backfills, ReplacingMergeTree validation, schema changes, deletes, and production troubleshooting. Use it alongside the current product documentation because connector behavior and support boundaries can change.
The managed-service questions that matter
Managed does not mean ānothing to operate.ā It means the location of the operations changes. Before choosing Estuary Flow, verify:
- What state is retained, for how long, and how it is recovered.
- How a destination outage affects source capture and backlog.
- How deletes, updates, ordering, and retries converge in ClickHouse.
- Which schema changes are automatic, blocked, or destructive.
- Whether transformations run before or after durable capture.
- How backfills and partial reloads work.
- Which delivery guarantees apply to the service, connector, and final table separately.
- How the bill changes with source volume, retention, destinations, and replay.
Estuaryās page contains product claims such as sub-100ms pipeline positioning and cost comparisons. Those claims should be treated as vendor statements unless a benchmark defines the workload, boundary, version, and method. The right response is not to dismiss them; it is to test them under your own write rate and correctness requirements.
MaterializedPostgreSQL: the native-coupling option
MaterializedPostgreSQL is ClickHouseās native replication path for PostgreSQL. The current ClickHouse MaterializedPostgreSQL documentation describes an initial snapshot, acquisition of a PostgreSQL log sequence number, and subsequent application of updates from the PostgreSQL WAL through the logical replication protocol.

The database-engine flow is conceptually direct:
That simplicity is real, but it comes with coupling. The source and destination must satisfy the engineās requirements, and the behavior of schema changes, tables, replication slots, failover, and target semantics matters more because there is no independent event platform absorbing those concerns.
What MaterializedPostgreSQL does well
The native path can be attractive when:
- ClickHouse is the primary destination.
- The deployment supports the engine.
- The team wants fewer external components.
- The source schema is predictable.
- The workload fits the engineās supported key and replication model.
- A direct source-to-destination relationship is more useful than a reusable event backbone.
The current documentation provides a precise list of boundaries. New PostgreSQL tables are not automatically added to an existing replication setup. PostgreSQL logical replication does not replicate DDL; breaking schema changes can stop table updates and may require a complete reload path. The documentation also notes requirements around logical WAL, replication slots, replica identity, and supported table keys.
The current table-engine documentation states that the engine is experimental, is not supported in ClickHouse Cloud, requires PostgreSQL 11 or later, and does not support TOAST values in the documented path. It also exposes _version and _sign virtual columns, which help represent freshness and deletion state.
The deployment-model trap
The native engine is not a universal answer for āPostgres to ClickHouse.ā ClickHouseās current documentation displays a Cloud-not-supported status for the MaterializedPostgreSQL database and table engines and directs ClickHouse Cloud users toward ClickPipes for PostgreSQL replication.
That one detail can change the entire recommendation. A self-managed ClickHouse deployment and a ClickHouse Cloud deployment should not be evaluated with the same assumption set.
The native path also deserves careful failover planning. ClickHouse documents that logical replication slots on a PostgreSQL primary are not automatically available after a standby is promoted. A managed slot and snapshot approach is described, but it should be used only when the operator understands the source failover design and the consequences for recovery.
The comparison that actually matters
The table below is designed as a decision aid, not as a claim that one product wins every row.
| Criterion | Debezium | Estuary Flow | MaterializedPostgreSQL |
|---|---|---|---|
| Core model | Composable source CDC and event streaming | Managed capture and materialization | Native ClickHouse replication engine |
| Common topology | PostgreSQL ā Debezium ā Kafka ā sink | PostgreSQL ā managed capture ā ClickHouse | PostgreSQL ā ClickHouse native engine |
| Kafka | Common in Kafka Connect deployments, but not required by every Debezium runtime | User-managed Kafka is not central to the direct managed path; verify connector options | Not required for the native path |
| Initial snapshot | Documented snapshot modes and incremental snapshots; version/configuration sensitive | Managed workflow; verify parallelism, retention, and backfill behavior | Native snapshot followed by WAL updates |
| Multiple destinations | Strong fit when Kafka is already a shared event backbone | Strong fit when managed fan-out is supported for the workload | Not its primary purpose |
| Update/delete handling | Requires sink and ClickHouse table-model design | Verify merge/delta and delete mode for the chosen connector | Uses native engine semantics, including documented version/sign behavior |
| Schema evolution | Flexible but distributed across source, events, converters, and sink | Managed schema policy; verify breaking-change behavior | DDL is not replicated; breaking changes can stop updates |
| Replay and recovery | Kafka and connector offsets can support replay, but the team operates the system | Service-specific; verify retention and recovery guarantees | Tightly coupled to source slot/WAL and native-engine behavior |
| Observability | Many metrics across source, connector, broker, consumer, sink, and target | Platform-level metrics; verify depth and exportability | Native system views plus ClickHouse and PostgreSQL monitoring |
| Deployment flexibility | High across Kafka Connect, Server, and Engine patterns | Depends on service and connector availability | Depends on ClickHouse and PostgreSQL support boundaries |
| Best fit | Existing streaming platform and multiple consumers | Managed-first teams and lower visible infrastructure burden | Supported native path with a simple topology |
| Main risk | Large operational surface area and sink complexity | Service dependency, pricing, and opaque boundaries | Version sensitivity, schema limits, failover, and tight coupling |
Decide by scenario, not by feature count

Scenario 1: A few tables and no Kafka
Start with Estuary Flow and the supported native ClickHouse path. The question is not āCan Debezium do this?ā It can. The question is whether the value of Kafka, Connect, topic retention, and replay justifies operating them for this workload.
A managed service may reduce setup effort. The native engine may reduce the number of moving parts. Both still need source permissions, WAL and replication configuration, target validation, schema decisions, and a recovery plan.
Scenario 2: Kafka is already a platform capability
Debezium becomes more attractive when Kafka, Connect, schema governance, monitoring, and on-call ownership already exist. The team can reuse established patterns, and the CDC stream can serve more than ClickHouse.
Do not treat āwe already have Kafkaā as a free decision. Confirm that the ClickHouse sink, converters, topic naming, update/delete model, and operational runbooks are already understood. Otherwise, the existing platform may reduce infrastructure duplication while increasing sink-debugging time.
Scenario 3: ClickHouse Cloud is the destination
Treat ClickHouse Cloud as a separate deployment case. ClickHouseās current ClickPipes PostgreSQL documentation covers source-provider prerequisites, connection networking, TLS, SSH tunneling, replication-slot selection, table selection, and parallel initial-load controls. It also warns that common PostgreSQL proxies such as PgBouncer and RDS Proxy are not supported for CDC-based replication in that setup.
The practical shortlist is therefore not simply ānative versus Debezium.ā It may include ClickPipes, a supported managed platform, or an externally operated CDC route. Check current Cloud support before building around the self-managed MaterializedPostgreSQL engine.
Scenario 4: Self-managed ClickHouse is required
MaterializedPostgreSQL deserves a serious evaluation when you want to keep the architecture close to the databases. But examine its boundaries before calling it simple: table keys, replica identity, WAL, replication slots, DDL, new-table discovery, TOAST behavior, backups, and failover.
Debezium may be a better fit when self-managed ClickHouse is only one of several consumers or when the team needs a durable event stream independent of ClickHouseās native engine.
Scenario 5: The workload is update- and delete-heavy
This is where the target model matters more than the source connector. ClickHouse is optimized for analytical reads and immutable-style inserts; it is not PostgreSQL with a different wire protocol. The official ClickHouse CDC guidance explains how ReplacingMergeTree can represent newer versions of rows and deletion markers, while also discussing the performance implications of merge timing and FINAL.
Here is a minimal ClickHouse table design for a CDC-fed orders table. The ORDER BY expression defines row identity for deduplication, while version tells ClickHouse which copy is newer. The is_deleted flag marks a tombstone. The current ClickHouse reference documents this ReplacingMergeTree(ver, is_deleted) signature and notes that is_deleted requires a version column.
SQL:
CREATE TABLE default.orders_cdc
(
id UInt64,
user_id UInt64,
status LowCardinality(String),
total_amount Decimal(18, 2),
updated_at DateTime64(3, 'UTC'),
version UInt64,
is_deleted UInt8
)
ENGINE = ReplacingMergeTree(version, is_deleted)
PRIMARY KEY id
ORDER BY id;
For a real CDC pipeline, version should come from a source ordering value that is monotonic for the row, such as a connector sequence or WAL position when the selected integration exposes one. A wall-clock updated_at column can be useful for analytics, but it is not automatically a safe conflict-resolution version if clocks tie or events arrive out of order.
The following statements show the row-state pattern. They are valid ClickHouse SQL examples, but the values and versioning strategy are illustrative; map them to the event fields emitted by your chosen CDC path.
SQL:
-- Initial state
INSERT INTO orders_cdc (id, status, updated_at, version, is_deleted)
VALUES (42, 'pending', '2026-08-24 09:00:00.000', 100, 0);
-- UPDATE: insert a newer copy of the same logical row
INSERT INTO orders_cdc (id, status, updated_at, version, is_deleted)
VALUES (42, 'paid', '2026-08-24 09:00:02.000', 101, 0);
-- DELETE: insert a newer tombstone for the same logical row
INSERT INTO orders_cdc (id, status, updated_at, version, is_deleted)
VALUES (42, 'paid', '2026-08-24 09:00:05.000', 102, 1);
-- Query the current state after query-time deduplication
SELECT id, status, updated_at
FROM orders_cdc FINAL
WHERE id = 42;
After the delete row wins, the final query returns no visible orders_cdc row for id = 42. Without FINAL, background merges may not yet have reconciled all duplicate versions, so a plain query can return stale or duplicate data. ClickHouse also documents that delete rows are retained by default during ordinary merges; cleanup is a separate, advanced operation with additional safety conditions.
Test the entire chain with:
- An INSERT.
- An UPDATE to a non-key column.
- An UPDATE to a key column.
- A DELETE.
- A duplicate delivery.
- An out-of-order delivery.
- A query executed before and after background merges.
A tool that captures the event correctly can still produce an analytical table that is wrong for the way your users query it.
PostgreSQL REPLICA IDENTITY: the delete and before-image trap
PostgreSQL needs a replica identity to identify the source row for UPDATE and DELETE operations. By default, that is the primary key; a suitable unique index can also be used. REPLICA IDENTITY FULL makes the entire old row available as the identity, but PostgreSQL describes it as a fallback when no better key exists because searching without a suitable index can be inefficient.
The important correction is that REPLICA IDENTITY FULL is not automatically required for every delete or primary-key update. It is needed when the selected capture and downstream logic require the complete old row and the existing identity does not provide enough information. For a Debezium pipeline, the exact before content depends on the tableās replica-identity setting and the connectorās event mapping.
SQL:
-- Use only when the downstream CDC contract genuinely needs the old row.
ALTER TABLE public.orders REPLICA IDENTITY FULL;
-- Return to the default identity behavior when a primary key is sufficient.
ALTER TABLE public.orders REPLICA IDENTITY DEFAULT;
FULL has a real source-side cost. PostgreSQLās current WAL documentation states that logical WAL increases WAL volume particularly when many tables use REPLICA IDENTITY FULL and many UPDATE or DELETE statements run. Measure WAL bytes, slot lag, write latency, and downstream event size under representative load before enabling it broadly.
A practical production rule is to keep a primary key or suitable replica-identity index wherever possible. Enable FULL selectively for tables whose consumers need complete old-row values, and include the setting in the table-by-table CDC contract rather than hiding it in a generic connector recipe.
Scenario 6: You need several downstream consumers
Debezium plus Kafka has a natural advantage when the change stream is a product in its own right. Search, warehouses, caches, operational services, and ClickHouse can consume the same event backbone.
Estuary Flow may be a better fit if managed fan-out and centralized materialization meet the requirements. MaterializedPostgreSQL is usually evaluated as a direct replication path, not as a general-purpose event distribution layer.
Scenario 7: Schema changes happen often
Ask for a change-by-change matrix. āSupports schema evolutionā is not precise enough.
| Schema event | Questions to ask |
|---|---|
| Add a nullable column | Is it detected automatically? When does the target schema change? |
| Add a required column | What default or backfill is required? |
| Widen a type | Is the event accepted by the sink and target table? |
| Change a type incompatibly | Does the pipeline pause, fail, or coerce values? |
| Rename a column | Is it treated as a position change, a new field, or an unsupported DDL event? |
| Drop a column | Are historical rows and downstream consumers affected? |
| Add a new source table | Is it discovered automatically or attached/configured manually? |
| Change a TOAST value | Is the value captured correctly in the selected path? |
MaterializedPostgreSQL is the clearest example of why this matters: the current ClickHouse documentation states that DDL is not replicated and that breaking changes can stop updates.
PostgreSQL-to-ClickHouse data-type mapping: use a contract, not a guess
The mapping depends on the path. A PostgreSQL value may pass through logical decoding, a Debezium event, a Kafka converter, a sink connector, and a ClickHouse table definition before it becomes a queryable column. The following table is a practical starting point for design review, not a universal automatic mapping.
| PostgreSQL type | Common ClickHouse target starting point | What can go wrong | Production check |
|---|---|---|---|
TIMESTAMP WITH TIME ZONE / timestamptz | DateTime64(3, 'UTC') when millisecond precision is sufficient | Time-zone normalization, precision loss, or a converter emitting a string | Confirm source session/time-zone rules, precision, and the connectorās temporal mapping. |
TIMESTAMP WITHOUT TIME ZONE | DateTime64(3) with an explicitly documented interpretation | A timestamp without a zone can be misread as UTC or local time | Define the business time zone before creating the target table. |
NUMERIC(p,s) | Decimal(p,s) when precision and scale are bounded | Overflow, scale mismatch, or arbitrary-precision values that do not fit | Test maximum precision and rounding; choose a wider Decimal type or String when required. |
UUID | ClickHouse UUID when the sink preserves a valid UUID representation; otherwise String as an interoperability fallback | Silent string coercion, invalid values, or inconsistent converter behavior | Verify the serialized record and target DDL; do not assume a native UUID mapping. |
JSONB | String plus JSON functions for a conservative cross-connector path; ClickHouse JSON only after version and feature checks | Nested schema drift, unsupported logical types, or expensive parsing | Decide whether the field is queried structurally or stored opaquely, then benchmark representative documents. |
BOOLEAN | ClickHouse Bool or UInt8, depending on the selected sink and schema contract | Converter emits a boolean while the target expects an integer, or vice versa | Inspect the serialized type and use an explicit mapping. |
| PostgreSQL arrays | Array(T) when the element type is supported | Arrays of unsupported or nested types can fail conversion | Test null elements, empty arrays, and the exact element mapping. |
BYTEA | String or a documented binary representation | Hex/base64 expansion can increase storage and change semantics | Decide whether the data is binary, encoded text, or a field to exclude. |
The official ClickHouse Kafka sink documentation lists supported Kafka Connect-to-ClickHouse types and explains that the converter and target schema matter. The Altinity connectorās data-type documentation also maintains path-specific mapping information for PostgreSQL and ClickHouse. Treat these tables as integration contracts: validate the exact Debezium format, converter, sink version, and ClickHouse DDL together.
A particularly common mistake is to treat JSONB, UUID, and time zones as cosmetic details. They are contract decisions. Make them explicit before the first snapshot, because changing a type after the target is populated can require a reload or a parallel table migration.
Initial load is a separate product decision
Steady-state CDC latency gets the attention because it is easy to market. Initial load often determines whether the project reaches production.

A large snapshot can create source pressure, consume connections, increase WAL retention, and delay the point at which the analytical copy is useful. A pipeline that looks fast after the snapshot may still take too long to become trustworthy.
A practical initial-load test
- Record source row counts and a sample of deterministic checksums.
- Start the snapshot under a representative write workload.
- Measure source CPU, I/O, connections, transaction duration, and WAL growth.
- Record time to first usable table and time to full catch-up.
- Introduce updates and deletes while the snapshot is running.
- Stop and restart the pipeline.
- Compare final row state, delete state, and query-visible freshness.
Debeziumās current documentation describes incremental snapshots that can run alongside streamed changes and resume after interruption. ClickHouse ClickPipes exposes settings for parallel initial-load workers and snapshot partitioning.
MaterializedPostgreSQLās native snapshot and reload behavior must be evaluated against the current engine documentation and your failover design.
How to validate correctness end to end
Use four independent checkpoints:
| Checkpoint | What it proves | Example evidence |
|---|---|---|
| Source capture | PostgreSQL changes are exposed to the CDC reader | WAL position, connector event, or managed-capture status |
| Transport | The event is durably routed or retained | Kafka offset/topic record or managed-service state |
| Sink ingestion | ClickHouse accepted the event | Sink metrics, rejected-record logs, target insert count |
| Query-visible state | The analytical result matches the intended source state | Key-level comparison after merges and deletes |
An illustrative update event might conceptually look like this:
JSON:
{
"before": {"id": 42, "status": "pending"},
"after": {"id": 42, "status": "paid"},
"operation": "update"
}This is a conceptual example, not a drop-in connector payload. The exact event envelope depends on the selected capture and sink configuration. The important point is that the destination must know how to interpret the old state, new state, operation type, key, ordering, and version information.
For every test row, compare the source and target by key. Check whether a delete is represented by a missing row, a tombstone, a sign column, a soft-delete flag, or a versioned record. Then measure the time until the query result becomes correct, not merely the time until a message appears in a topic.
Reliability: slots, WAL, failover, and recovery
Logical replication creates a source-side dependency that deserves monitoring. If a consumer cannot advance its replication slot, PostgreSQL may retain WAL longer than expected. Long-running transactions, a stopped connector, a destination outage, or an unplanned failover can turn a small delay into a source-storage problem.

Questions every design should answer
- Who owns the replication slot?
- How is slot lag measured and alerted?
- What happens if ClickHouse is unavailable for an hour?
- What happens if the connector stops during the initial snapshot?
- Can the pipeline resume from a durable position?
- Can one table be reloaded without rebuilding everything?
- What happens after PostgreSQL promotes a standby?
- How do you detect that a table is stale even though the connector is healthy?
- How are duplicate, late, and rejected events handled?
Debezium documents restart and snapshot behavior, including how offsets and snapshots interact after failure. ClickHouse documents the special failover considerations for MaterializedPostgreSQL slots and the careful use of externally managed slots and snapshots. Managed platforms require the same questions, even when the service operates the underlying infrastructure for you.
Observability, security, and total cost

Observability
A useful dashboard should combine source, pipeline, and destination signals:
- PostgreSQL WAL position and slot backlog.
- Connector or capture health.
- Kafka consumer lag, if Kafka is used.
- Sink errors and rejected records.
- ClickHouse insert failures.
- Target row counts and duplicate density.
- Last query-visible change per table.
- Merge backlog or freshness delay.
- Schema-drift and DDL events.
Do not report only connector uptime. A connector can be healthy while the target table is stale or semantically wrong.
Security and networking
Use a dedicated replication user with the minimum privileges required by the chosen path. Keep credentials out of code and screenshots. Verify TLS, certificate validation, firewall rules, private connectivity, SSH tunnel behavior, secret rotation, and audit requirements.
ClickHouse ClickPipes documents TLS controls, certificate verification, IP allowlisting, SSH tunneling, and private connectivity options for the Cloud workflow. MaterializedPostgreSQL documents TLS parameters passed to libpq and the permissions involved in publications and replication slots.
Total cost of ownership
Avoid reducing the decision to a connector price. Model:
- Infrastructure and managed-service fees.
- Kafka brokers, Connect workers, and storage.
- Engineering time for schema and sink maintenance.
- On-call and incident response.
- Source database pressure.
- Retention, replay, and backfill costs.
- Network transfer and private connectivity.
- Vendor lock-in and migration effort.
For a small pipeline, a managed service can be economical because it replaces engineering and on-call work. For a large event platform, the same service may duplicate capabilities you already operate. The answer depends on the cost of the whole operating model.
A fair benchmark scorecard
Do not compare tools using one vendorās āreal-timeā claim against another toolās āexactly-onceā claim. Run the same workload and document the boundary.
| Test | Measurement |
|---|---|
| Initial snapshot | Time to first usable table; time to full consistency |
| Append-only stream | Sustained events per second and p50/p95 freshness |
| Update-heavy stream | Correct final state, duplicate density, merge delay |
| Delete-heavy stream | Delete convergence and query behavior |
| Schema addition | Time to target-schema availability and failure behavior |
| Incompatible schema change | Pause, reject, coerce, or reload behavior |
| Destination outage | Backlog growth, recovery time, and lost-event check |
| Source failover | Slot continuity, restart behavior, and required reload |
| Backfill | Operator steps, source pressure, and convergence time |
| Cost | Infrastructure, service, storage, network, and operator hours |
What not to claim
Do not write that one tool is universally faster, cheaper, safer, or more reliable unless the article includes a reproducible benchmark with versions, dataset shape, write rate, network, hardware, configuration, and correctness results. Vendor demos and community reports are useful evidence for questions to test; they are not substitutes for the test.
Before you choose a connector
Free Engineering ToolkitCan your CDC design prove correctness after a replay?
The free readiness kit turns this comparison into an actionable implementation exercise: score your architecture, run source preflights, test UPDATEs and DELETEs, measure query-visible freshness, and document your recovery path.
| Included in Kit | What it helps you decide & test |
|---|---|
| Decision Scorecard | Which operating model fits your team, infrastructure, and budget? |
| SQL Validation Pack | Does the target converge after updates, deletes, replay, and asynchronous merges? |
| Recovery Runbook | Step-by-step procedures when slots lag, sinks fail, or PostgreSQL promotes a standby. |
Common mistakes when sending PostgreSQL CDC to ClickHouse

1. Treating Debezium as synonymous with Kafka
Kafka Connect is the common Debezium deployment model, but Debezium Server and Debezium Engine change the topology. Decide whether you need Kafka itself or only Debeziumās capture capability.
2. Assuming capture success means replica success
Trace the event through source, transport, sink, target table, merge, and query. An event that exists in Kafka can still fail to become a visible ClickHouse row.
3. Ignoring initial load
Measure snapshot duration, source pressure, and catch-up. A low steady-state lag does not compensate for a copy that never becomes trustworthy.
4. Forgetting replication-slot monitoring
A stopped consumer can have consequences on PostgreSQL storage. Alert on backlog and WAL retention, not only connector process health.
5. Treating ClickHouse like an OLTP database
Updates and deletes often require versioned or append-and-merge designs. Test the table engine, key, merge behavior, and query pattern together.
6. Assuming DDL automatically propagates
Logical replication and target connectors do not make every schema change safe. Build a change matrix and define the reload path.
7. Using FINAL as a free correctness switch
FINAL can affect query cost. Benchmark the real query workload and consider how data is partitioned and merged.
8. Trusting historical product advice
MaterializedPostgreSQL guidance changes with ClickHouse releases and deployment models. Current official documentation should outrank old forum comments and old blog posts.
9. Comparing latency without defining the boundary
āSub-secondā may mean capture, delivery, or query-visible freshness. Name the start and end timestamps.
10. Copying production credentials into examples
Use placeholders and explain secret management. A readable tutorial is not a reason to publish an unsafe configuration.
Before and after: how the decision should change
A weak CDC decision starts with the connector. A stronger one starts with the state the business needs to query and works backward through the architecture.
| Before | After |
|---|---|
| āWhich tool has the lowest latency?ā | āWhat is the maximum commit-to-query-visible freshness we need, and how will we measure it?ā |
| āCan it replicate PostgreSQL?ā | āCan it load the initial state, capture changes, apply updates and deletes, and prove convergence?ā |
| āDoes it support schema evolution?ā | āWhich exact DDL changes are safe, automatic, blocked, or reload-only?ā |
| āDo we need Kafka?ā | āDo we need replay, multiple consumers, durable buffering, or a platform we already operate?ā |
| āIs the connector running?ā | āAre source capture, transport, sink ingestion, merges, and query results all healthy?ā |
| āIs the product managed?ā | āWhich responsibilities moved to the service, and what do retention, recovery, and pricing cover?ā |
The outcome is a more durable decision: choose the architecture that makes correctness, recovery, and ownership visible enough to operate.
The practical verdict
The most useful way to choose among Debezium, Estuary Flow, and MaterializedPostgreSQL is to ask five questions in order:
- Where will the data live? ClickHouse Cloud and self-managed ClickHouse can produce different supported choices.
- Who will operate the middle layer? Kafka, Connect, and sink ownership is a real cost.
- What is the workload shape? Table count, row volume, updates, deletes, and snapshot size determine fit.
- How much schema change is normal? A stable source is a different problem from a constantly evolving application database.
- What does recovery mean? Restarting a connector is not the same as proving that the target is complete and correct.
The conditional recommendation
Debezium is the strongest first candidate when Kafka is already strategic, several consumers need the same event stream, or engineers need control over runtime and event flow. Its price is operational surface area.
Estuary Flow is the strongest first candidate when the team prefers managed CDC and wants to minimize self-managed streaming infrastructure. Its price is dependence on service behavior, pricing, recovery semantics, and product boundaries that must be verified for the workload.
MaterializedPostgreSQL is the strongest first candidate when the current native engine is supported for the chosen ClickHouse deployment, the source schema is manageable, and a direct topology is more valuable than a reusable event backbone. Its price is tighter coupling to PostgreSQL and ClickHouse behavior, especially around DDL, slots, failover, and target semantics.
Open the practical decision helper
If you answer āyes,ā follow this path
- We already operate Kafka and need more than ClickHouse: Evaluate Debezium first, then benchmark the sink and target model.
- We do not operate Kafka and only need a few tables: Compare Estuary Flow with the supported native path before adding a streaming platform.
- We use ClickHouse Cloud: Start with currently supported Cloud ingestion paths and treat MaterializedPostgreSQL as a separate support question.
- We need frequent UPDATEs and DELETEs: Reject any tool until it passes a target-correctness test with your actual table keys and query patterns.
- We expect frequent schema changes: Require a change matrix, reload procedure, and recovery test from every candidate.
- We need several destinations: Prefer a design that makes replay, fan-out, and schema governance explicit.
Conclusion
Debezium, Estuary Flow, and MaterializedPostgreSQL solve the same broad problem through different operating models. Debezium gives you control and an extensible event architecture. Estuary Flow reduces the infrastructure you have to assemble and operate.
MaterializedPostgreSQL keeps the path close to ClickHouse and PostgreSQL, but asks you to respect its current compatibility and schema boundaries.
The winning architecture is not the one with the most features. It is the one that can load the initial state, process changes correctly, survive interruptions, handle schema evolution, and leave your team with a recovery plan it can execute at 2 a.m.
Before choosing, run a controlled proof with your real table keys, write rates, update/delete mix, schema-change patterns, deployment model, and query workload. Compare correctness, time to trustworthy data, recovery, and total operating effort before you compare raw latency.
Ready to test the architecture?
Before calling a PostgreSQL-to-ClickHouse pipeline production-ready, validate the source slot, WAL budget, replica identity, sink mapping, target DDL, duplicate behavior, delete convergence, schema changes, restart, outage recovery, and query-visible freshness.
The free ClickHouse CDC Production Readiness Kit puts those checks into an editable workbook, SQL files, a benchmark worksheet, and a recovery runbook.
Frequently Asked Questions
Was this article helpful?









