Education
15 min read

What is CDC in data engineering? Change data capture explained

What is CDC in data engineering? Learn how change data capture records database changes, differs from ETL and incremental loading, and when to use it.

Arsalan Noorafkan

Developer Advocate

Quick answer: CDC stands for change data capture. It is a way to track inserts, updates, and deletes in a source system, then move those changes into another system without reloading the whole table every time.

The shortest version:

source database changes -> CDC process -> warehouse, lake, stream, or another database

If an order is inserted in Postgres, CDC can send that new order to BigQuery. If a customer row is updated in MySQL, CDC can send the updated version to Snowflake. If an account is deleted in SQL Server, CDC can preserve that delete as an event so the destination does not quietly drift away from the source.

That's the useful bit. CDC is not just "faster ETL". It changes the shape of the ingestion problem: instead of asking "what does the full table look like now?", you ask "what changed since the last point I safely processed?"

This article covers the broader capture method. For the continuous, low-latency delivery model, see CDC streaming.

For data teams, this matters because most company data does not sit still. Product events arrive, payments settle, subscriptions change status, tickets get merged, rows get corrected, and someone eventually deletes the thing everyone assumed would never be deleted. The classic nightly full refresh works for small tables. It gets painful once tables are large, freshness matters, or downstream systems need a proper history of changes.

What CDC means

Change data capture is the process of detecting row-level changes in a source system and making those changes available to another system.

A CDC event usually answers a few practical questions:

  • Which table changed?
  • Which row changed?
  • Was it an insert, update, or delete?
  • What did the row look like before?
  • What does the row look like after?
  • When did the change happen?
  • Where in the source log did this change come from?

A simplified CDC event might look like this:

{
  "table": "public.orders",
  "operation": "update",
  "primary_key": { "order_id": 1042 },
  "before": {
    "status": "pending",
    "updated_at": "2026-07-13T08:14:10Z"
  },
  "after": {
    "status": "paid",
    "updated_at": "2026-07-13T08:16:03Z"
  },
  "source_position": "log-sequence-number-or-binlog-offset"
}

That source_position part is easy to ignore when you are learning CDC, but it is one of the most important pieces. A CDC pipeline needs to know where it stopped so it can resume without skipping changes or processing the same change incorrectly. In PostgreSQL, this is tied to logical decoding and replication slots. In MySQL, it is commonly tied to the binary log. In SQL Server, CDC reads from the transaction log into change tables.

The names vary by database, but the pattern is similar: the database already records changes so it can commit transactions, recover from failure, and replicate data. CDC uses that record as the source of truth for downstream movement.

How CDC works

There are a few ways to capture changes, but log-based CDC is the one most engineers mean when they say CDC.

1. The database writes a change

An application inserts, updates, or deletes a row. The database commits the transaction and records it in its internal log.

Examples:

  • PostgreSQL exposes changes through logical decoding, which can stream SQL-level modifications to external consumers.
  • MySQL records changes in the binary log, often called the binlog.
  • SQL Server CDC reads from the transaction log and stores changes in relational change tables.
  • Debezium connectors commonly capture MySQL changes from the binlog and PostgreSQL changes from a logical replication stream, as described in the Debezium architecture docs.

2. A CDC reader consumes the log

The CDC reader connects to the source database and reads committed changes in order. It does not need to run select * from orders every five minutes. It reads the database's change stream.

This usually reduces source load compared with full-table extraction, especially when a table is large but only a small percentage of rows change during each sync.

3. The pipeline stores an offset

The pipeline records the last safe position it processed. That offset might be a log sequence number, binlog file and position, timestamp plus version, or another source-specific cursor.

This is what lets the pipeline restart after a deploy, network failure, worker crash, or source maintenance window.

4. The destination applies the changes

The destination might receive the changes as:

  • an append-only raw change table
  • a current-state replica table
  • a stream topic
  • a slowly changing dimension table
  • a queue for downstream applications

Analytics teams often keep both:

  • raw CDC events for auditability and replay
  • current tables for normal BI, AI analysis, dashboards, and modelling

That split is boring, but it saves you later. Raw events are useful when something goes wrong and you need to replay or explain history. Current tables are useful because most business users want to query "orders" rather than reconstruct a table from every historical mutation.

CDC vs ETL vs ELT

CDC is not a replacement for ETL or ELT. It is a method of extraction.

ConceptWhat it meansWhere CDC fits
ETLExtract, transform, loadCDC can be the extract step
ELTExtract, load, transformCDC can load raw changes first, then transform in the warehouse
Data ingestionMoving data from source to destinationCDC is one ingestion strategy
ReplicationKeeping another system close to the sourceCDC may power replication, but it is not limited to source-shaped copies
StreamingMoving events continuouslyCDC can produce a stream, but CDC can also be consumed in batches

The difference sounds pedantic until you design the pipeline.

If you say "we need ETL", you still have to decide whether extraction is full refresh, timestamp incremental, API pagination, event export, or CDC. If you say "we need CDC", you still have to decide what happens after the changes land: raw storage, merges, transformations, checks, lineage, documentation, and access control.

This is why CDC is usually one part of a broader data platform, not the whole platform.

CDC vs incremental loading

CDC and incremental loading overlap, but they are not the same thing.

Incremental loading means "only load new or changed data since the last run." CDC is one way to do that.

The common incremental strategies look like this:

StrategyHow it finds changesGood forMain risk
Timestamp cursorReads rows where updated_at > last_run_timeSimple tables with reliable timestampsMissed deletes, clock issues, late updates
Increasing IDReads rows where id > last_seen_idAppend-only tablesCannot detect updates or deletes
Full diffCompares source and destination snapshotsSmaller tables where correctness mattersExpensive at scale
Log-based CDCReads transaction logs or change streamsLarge mutable tables, low-latency syncsMore setup, permissions, and operational detail
Trigger-based CDCWrites changes through database triggersDatabases without usable logsAdds write-path overhead and schema complexity

If a table is append-only, an increasing ID cursor might be enough. If rows are updated and deleted all day, CDC becomes much more attractive.

The mistake is treating every table the same. A small reference table can be full-refreshed. A huge orders table probably should not be. An event table may only need append mode. A customer table with merges, deletes, and compliance requirements may need CDC or SCD Type 2.

Types of CDC

Log-based CDC

This is the usual preferred option for production databases. The CDC tool reads the transaction log, binlog, write-ahead log, redo log, or logical replication stream.

Why teams like it:

  • lower source query load than repeated full scans
  • captures inserts, updates, and deletes
  • preserves ordering better than timestamp scans
  • can support lower-latency syncs
  • usually does not require changing application code

The tradeoff: you need source-specific setup. Permissions, retention, replication slots, binlog settings, replica identity, networking, and failover behaviour matter.

Trigger-based CDC

Trigger-based CDC adds database triggers that write changes to audit or shadow tables. A pipeline then reads those tables.

This can work, especially when the database does not expose a useful log. But it adds logic to the write path. That means more performance risk, more migration work, and more things to review when schema changes happen.

Query-based CDC

Query-based CDC polls the source with a cursor, usually updated_at, created_at, or an incrementing ID.

This is the easiest model to understand and often the first one teams implement. It is also the easiest one to get subtly wrong.

The usual problems:

  • hard deletes disappear unless you soft-delete rows
  • updates can be missed if timestamps are unreliable
  • backfilled rows can fall outside the cursor window
  • bulk updates can overload the next sync
  • clock and timezone issues create awkward edge cases

Query-based incremental loading is still useful. It just should not be called "proper CDC" unless it really captures the mutations you care about.

When CDC is worth it

CDC is worth considering when at least one of these is true:

  • tables are too large for regular full refreshes
  • downstream data needs to be fresh within minutes
  • updates and deletes matter
  • you need an audit trail of row-level changes
  • you want to replicate operational database changes into a warehouse or lakehouse
  • source systems are sensitive and you want to reduce repeated heavy reads
  • downstream consumers need to replay events from a known point

Good CDC use cases:

  • syncing Postgres, MySQL, or SQL Server into Snowflake, BigQuery, Redshift, Databricks, or DuckDB
  • keeping customer, subscription, payment, order, ticket, or inventory tables fresh
  • feeding event-driven systems from database mutations
  • maintaining current-state and historical tables side by side
  • reducing batch windows for large mutable datasets

CDC is especially useful when the business keeps asking why yesterday's dashboard is not fresh enough, but the data team knows that full-refreshing the source every 15 minutes would be irresponsible.

If you search for "CDC tools", you will usually see the same names come up: Debezium, Fivetran, Airbyte, Estuary Flow, AWS Database Migration Service, Google Datastream, Oracle GoldenGate, Qlik Replicate, and now Bruin with ingestr for code-first CDC inside a governed data pipeline.

They are not interchangeable. Some are CDC engines. Some are managed ELT platforms. Some are cloud migration services that happen to support ongoing replication. Some are better when Kafka is already part of your stack. Some are better when your team wants a YAML asset in Git and a scheduler around it.

Here is the practical split.

ToolBest fitWhat to watch
DebeziumOpen-source log-based CDC into Kafka Connect, Debezium Server, or streaming infrastructureYou operate the runtime, connectors, offsets, schema changes, and downstream sinks
FivetranManaged database replication into warehouses with less infrastructure workCost, vendor control, sync frequency, and connector-specific behaviour
AirbyteOpen-source or managed connector platform with CDC support for common databasesAirbyte's CDC model is scheduled sync, not an infinite stream, so log retention and sync cadence matter
Estuary FlowStreaming-first CDC and materialization for low-latency data movementAnother streaming platform to operate, govern, and connect to the rest of your stack
AWS DMSDatabase migration and ongoing replication inside AWSAWS explicitly notes that DMS CDC is not real-time replication and latency depends on workload, network, replication instance, and target capacity
Google DatastreamServerless CDC on Google Cloud, especially into BigQuery and Cloud StorageStrong fit for GCP-centred stacks, less portable if your CDC architecture needs to stay cloud-neutral
Oracle GoldenGateEnterprise replication, Oracle-heavy estates, and heterogeneous database environmentsPowerful, but usually more enterprise-ops heavy than a simple warehouse ingestion job
Qlik ReplicateEnterprise CDC and replication across many source and target systemsSimilar tradeoff: broad enterprise capability, but with platform cost and operational ownership
Bruin + ingestrCode-first ingestion assets, CDC, transformations, checks, lineage, and governance in one workflowBest when CDC should be part of a reviewed data pipeline, not a disconnected sync job

Honestly, the right choice is less about the CDC acronym and more about the operating model.

If Kafka is already the centre of the architecture, Debezium is a natural fit. If the team wants a managed warehouse connector and does not want to run capture infrastructure, Fivetran or Airbyte may be the simpler path. If the project is a cloud migration, AWS DMS or Datastream can be the right boring answer. If the estate is Oracle-heavy or enterprise replication is the main job, GoldenGate or Qlik Replicate deserve a look.

And if the question is "how do we put CDC inside the same repo where we define transformations, tests, owners, metadata, and lineage?", that is where Bruin fits.

How Bruin supports CDC with ingestr

Bruin's CDC support lives in the ingestr asset type. In other words, CDC is not configured as a one-off side process that nobody can find later. It is an asset in the pipeline, alongside SQL assets, Python assets, checks, ownership metadata, and downstream lineage.

A simple PostgreSQL CDC asset looks like this:

name: raw.orders
type: ingestr
connection: bigquery

parameters:
  source_connection: pg_prod
  source_table: public.orders
  destination: bigquery
  cdc: "true"
  cdc_mode: stream

The Bruin docs describe CDC support for PostgreSQL, MySQL/MariaDB, Vitess, and PlanetScale sources through ingestr assets:

Under the hood, ingestr's CDC docs expose the lower-level source schemes and runtime controls. For example, PostgreSQL CDC can use postgres+cdc://, MySQL CDC can use mysql+cdc://, and PlanetScale CDC can use ps_mysql+cdc://. ingestr also has streaming flush controls like --flush-interval and --flush-records, and stream monitoring metrics for replication lag and durable row counts.

Bruin adds the pipeline layer around that:

  • CDC assets are defined in Git.
  • Destination application uses merge semantics for CDC, so updates and deletes can be applied by primary key.
  • Primary keys are determined from the source for CDC assets where the source exposes them.
  • Pipeline runs can include CDC ingestion, transformations, checks, and downstream assets in the same graph.
  • Bruin Cloud can add scheduling, catalog, lineage, access controls, SSO, audit logs, and observability around those assets.

That's the main difference. A CDC tool can move changes. A governed CDC pipeline also tells you who owns the data, which downstream models depend on it, what checks ran, what changed in Git, and whether the tables are trustworthy enough for dashboards or an AI data analyst.

When CDC is not worth it

CDC has a cost. Not always a vendor cost, but definitely an operational cost.

You may not need CDC when:

  • the table is tiny
  • the table is append-only
  • daily freshness is enough
  • deletes do not matter
  • a source API already gives reliable incremental exports
  • the source database team will not grant replication or log access
  • your downstream models are not ready to handle late-arriving changes

CDC can make a messy pipeline faster, but it will not make it governed.

If there is no ownership, no tests, no lineage, no clear schema-change policy, and no destination contract, CDC just moves the chaos more quickly. This is where teams get disappointed: they add a powerful capture layer, then discover their warehouse models still cannot explain what "active customer" means.

What can go wrong with CDC

The failure modes are not exotic. They are normal data engineering problems with sharper edges.

Schema changes

Source tables change. Columns are added, renamed, removed, widened, narrowed, or repurposed. CDC pipelines need a schema-change policy:

  • Should new columns appear automatically?
  • Should type changes be blocked?
  • Should the raw event stream preserve unknown fields?
  • Who reviews downstream model impact?

Without this, one application migration can break ingestion, transformations, dashboards, and AI answers at the same time.

Deletes

Deletes are the reason many timestamp-based incremental jobs lie.

If a row is physically deleted from the source, a normal updated_at query will not see it. CDC can capture delete events, but the destination still needs to decide what to do with them:

  • delete the row from the current table
  • mark it as deleted
  • keep it in raw history only
  • apply a retention policy

That choice is a business and governance decision, not just an engineering one.

Backfills and snapshots

Most CDC pipelines start with an initial snapshot, then switch to ongoing changes.

That handoff is critical. If the snapshot and log stream are not coordinated, you can miss changes that happen during the snapshot or apply duplicates after it.

Good CDC tools handle this carefully. Homegrown scripts often do not, mostly because the happy path looks deceptively simple.

Ordering and idempotency

CDC events need to be applied in a way that produces a correct destination state even if a worker retries. That usually means designing around primary keys, source positions, transaction boundaries, and idempotent merges.

If "run it again" creates duplicates, the pipeline is not finished.

Source retention

Database logs are not kept forever. If a CDC process stops for too long and the source removes the old log segment, the pipeline may no longer be able to resume from its saved offset. Then you are looking at a re-snapshot or some careful repair work.

This is why monitoring matters. CDC needs lag alerts, not just job-success alerts.

How CDC fits into a governed data pipeline

A practical CDC pipeline usually has these layers:

source database
  -> CDC capture
  -> raw change events
  -> current-state tables
  -> transformations
  -> checks
  -> catalog, lineage, dashboards, AI analyst

The capture layer is only the beginning.

For analytics and AI workflows, the downstream context is just as important:

  • catalog so people know what tables mean
  • lineage so changes can be traced from source to dashboard
  • quality checks so broken loads do not become trusted answers
  • asset tiers so important tables are handled differently from scratch work
  • audit trails so production changes have a review history
  • access controls so raw operational data is not exposed casually

This is the part Bruin cares a lot about. The open-source side gives you local, code-first pipeline work with Bruin CLI and ingestion with ingestr. Bruin Cloud adds orchestration, catalog, lineage, checks, access controls, SSO, audit logs, and observability around those workflows.

CDC is strongest when it is not a disconnected sync job. It should be visible inside the same workflow where transformations, checks, and downstream data products are reviewed.

A simple CDC decision checklist

Before choosing CDC, ask:

  1. Does the source expose a reliable change log or CDC feature?
  2. Can we get the permissions needed to read it?
  3. Do we need deletes, or only inserts and updates?
  4. Do we need raw history, current-state tables, or both?
  5. How fresh does the destination actually need to be?
  6. What happens when the schema changes?
  7. What happens when the pipeline is down for two hours?
  8. How do we monitor lag?
  9. Can the destination apply events idempotently?
  10. Who owns the downstream model if the source semantics change?

If those questions feel annoying, that's the point. CDC is not hard because the acronym is hard. It is hard because it touches database internals, pipeline reliability, schema contracts, and business meaning at the same time.

FAQ

What is CDC in data engineering?

CDC means change data capture. It is the process of identifying inserts, updates, and deletes in a source system and moving those changes to another system, usually a warehouse, lakehouse, stream, or operational database.

What is the difference between CDC and ETL?

ETL is the broader process of extracting, transforming, and loading data. CDC is a capture strategy inside that process. Instead of extracting a whole table every time, CDC captures only the rows that changed.

Is CDC the same as replication?

No. Replication usually tries to keep another database copy close to the source shape. CDC emits a stream or table of change events that downstream systems can transform, audit, replay, or merge into different models.

When should a team use CDC?

Use CDC when full refreshes are too slow, source tables are large, downstream data needs to stay fresh, or deletes and updates matter. It is especially useful for database-to-warehouse ingestion and event-driven data pipelines.

What is log-based CDC?

Log-based CDC reads the database transaction log, such as the PostgreSQL logical replication stream, MySQL binary log, or SQL Server transaction log, instead of repeatedly querying source tables for changes.

Popular CDC tools include Debezium, Fivetran, Airbyte, Estuary Flow, AWS Database Migration Service, Google Datastream, Oracle GoldenGate, Qlik Replicate, and Bruin with ingestr. The right choice depends on whether you want open-source streaming CDC, managed ELT, cloud migration replication, enterprise database replication, or CDC as part of a governed pipeline.

Does Bruin support CDC?

Yes. Bruin supports CDC through ingestr assets. Bruin docs describe CDC support for PostgreSQL, MySQL/MariaDB, Vitess, and PlanetScale sources using cdc: "true". Bruin keeps CDC in the same asset graph as transformations, checks, ownership metadata, catalog, lineage, and Cloud observability.

Does CDC require Kafka?

No. Kafka is common in CDC architectures, especially with Debezium, but it is not mandatory. CDC changes can flow into warehouses, object storage, queues, streams, or another database depending on the tool and destination.

Can CDC capture deletes?

Yes, proper CDC can capture deletes if the source and capture method support them. The destination still needs a clear policy for applying those deletes, preserving them in history, or marking rows as deleted.

Is CDC always real-time?

No. CDC can be near real-time, but it can also be consumed in micro-batches or scheduled jobs. The important part is that the pipeline reads changes from a reliable change source instead of repeatedly extracting the whole table.

The useful way to think about CDC

CDC is a better question to ask of operational data:

What changed, in what order, and how do we safely apply it downstream?

Once you think about it that way, the rest of the design gets clearer. You need a source of changes, a stored position, an idempotent destination write, a schema policy, monitoring, and enough governance that people can trust the tables built from those changes.

The capture part is technical. The trust part is the real work.