Streaming ETL With CDC and Materialized Views: Real-Time Without a New Data Stack
Data Engineering·By Islam Gamal··27 min read

Streaming ETL With CDC and Materialized Views: Real-Time Without a New Data Stack

Debezium, Kafka, and Postgres materialized views give you sub-minute freshness without rebuilding your warehouse — here's the architecture and its trade-offs.

Islam Gamal
Islam Gamal
AI · Data · Automation Engineer
TL;DR

Change Data Capture (CDC) turns your operational database's write-ahead log into an event stream. Combined with Kafka and either downstream materialized views or a streaming warehouse, it delivers sub-minute freshness without touching application code. Adopt it when nightly batch stops being enough — and understand the operational cost you're taking on.

Key takeaways
  • CDC captures every insert/update/delete from the source DB with no app changes.
  • Debezium + Kafka is the mature open-source pattern; managed alternatives exist.
  • Materialized views (Postgres, Snowflake, BigQuery) turn streams into queryable state.
  • Streaming warehouses (Materialize, RisingWave) are worth it when you need real-time joins.
  • Streaming's true cost is operational — schema evolution and backfills need real design.

Why streaming, and when

Nightly batch is fine until it isn't. The signals that you've outgrown it:

  • Business asks for 'today's numbers' before your batch runs.
  • A dashboard needs freshness under 15 minutes.
  • ML features need to reflect events within seconds.
  • You're triggering webhooks or workflows off DB changes without a clean pattern.

If none of these apply, don't stream — the operational tax is real. If several apply, CDC is usually the lowest-friction upgrade.

CDC in one paragraph

Every relational database maintains a write-ahead log (Postgres WAL, MySQL binlog, SQL Server transaction log). CDC tools read the log and emit each change as an event to a message system. Nothing in your application changes — the DB is the source of truth, the log is a natural event stream, and you're just consuming it.

The Debezium + Kafka pattern

# debezium connector config
{
  "name": "orders-cdc",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "prod-db",
    "database.port": "5432",
    "database.user": "debezium",
    "database.password": "...",
    "database.dbname": "app",
    "plugin.name": "pgoutput",
    "publication.autocreate.mode": "filtered",
    "table.include.list": "public.orders,public.line_items",
    "topic.prefix": "prod",
    "snapshot.mode": "initial",
    "tombstones.on.delete": "true"
  }
}

Debezium first takes a consistent snapshot of every included table, then tails the WAL. Every row change becomes a Kafka message on prod.public.orders. Consumers subscribe and update whatever downstream state they need.

Materialized views for the read side

A consumer reads the Kafka topic and maintains a downstream table you can query. For simple cases (denormalization, single-table filtered views), a Postgres materialized view refreshed on a schedule is enough:

create materialized view active_customers as
select customer_id, count(*) as orders, max(created_at) as last_order
from orders
where status = 'active'
group by 1;

-- refresh incrementally with pg_ivm, or fully every N minutes
refresh materialized view concurrently active_customers;

For complex real-time joins across streaming tables, standard MVs aren't enough. That's where streaming warehouses come in.

When to reach for Materialize or RisingWave

Streaming warehouses (Materialize, RisingWave, ksqlDB) maintain fully incremental materialized views over streams. You define a SQL query joining multiple CDC topics; the engine keeps the result up-to-date within milliseconds of each source change.

They shine when you need:

  • Real-time joins across 3+ streams (order + customer + product = an enriched view).
  • Sub-second freshness on aggregates.
  • Consistent snapshots — you never see a partial update mid-query.

They cost more per GB than a batch warehouse and are trickier to operate. Use them when you have a real real-time product, not for dashboards.

Schema evolution — where teams get burned

Your OLTP app renames a column. CDC dutifully emits messages with the new schema. Downstream consumers explode. Every serious streaming setup needs:

  • A schema registry (Confluent, Apicurio) with backward-compatibility enforcement.
  • PR review on OLTP migrations that touch published tables — with data engineers on the reviewer list.
  • A 'streaming contract' doc for each replicated table naming which downstream systems consume it.

Skip this and every DB migration becomes a downstream incident.

Backfills, snapshots, and disaster recovery

What happens when a downstream system is broken for a week? When you launch a new consumer that needs historical data? When Kafka retention is 7 days but the outage was 10?

  1. Set Kafka retention long enough to cover recovery scenarios (7-30 days is common).
  2. For historical data past retention, use Debezium's incremental snapshot to re-read a table without a full reload.
  3. For new consumers, backfill from the warehouse (batch) up to a chosen timestamp, then subscribe to the stream from that timestamp. Bootstrap + tail pattern.
  4. Document your recovery playbook. Rehearse it. It's the least fun tabletop until it's the most important one.
#CDC#Streaming#Debezium#Kafka#Materialized Views

Frequently asked

Can I skip Kafka and use Postgres LISTEN/NOTIFY?

For small scale, yes — see the event-driven-with-Postgres article. But NOTIFY is fire-and-forget and doesn't survive consumer downtime. For real CDC pipelines, Kafka (or Redpanda / Kinesis) is the durable buffer that makes everything else possible.

Does streaming replace my batch warehouse?

Rarely. Most teams end up with both — batch for historical analysis, stream for real-time slices. The unified lakehouse pattern (Iceberg, Delta) is where the two are converging.

How much does this cost to run?

Debezium on a small VM ($30/mo), Kafka on 3 broker nodes (~$400/mo self-managed, ~$1500/mo Confluent Cloud), plus consumer compute. Streaming warehouses add $1-5k/mo depending on scale. Budget a real ops engineer's attention on top.

Building something similar?

I help teams ship production-grade AI agents, n8n workflows, and data platforms. Let's talk about what you're building.

Work with me
Islam Gamal
Written by

Islam Gamal

AI, Data & Automation Engineer. I design and ship production AI agents, n8n workflows, and cloud data platforms — with a focus on reliability, cost, and measurable business impact. Founder of Tashghil and Tek bil Arabi.

More from Islam Gamal

Browse every article by Islam Gamal on the author page.