Change Data Feed (CDF) automatically records changes (INSERT / UPDATE / DELETE) to a Delta Table and efficiently propagates "what changed" to downstream pipelines and systems. It is commonly used for incremental processing between Silver and Gold layers, and for integration with external systems.
This article walks through enabling CDF, the meaning of each _change_type value, how to read CDF data in batch and streaming modes, the foreachBatch + MERGE pattern for downstream propagation, how CDF relates to Lakeflow Spark Declarative Pipelines APPLY CHANGES INTO, and the points the exam tends to ask about.
CDF is enabled per table. You can set it when creating a new table or by changing properties on an existing one. Only changes that occur after CDF is enabled are recorded — history from before enabling is not available.
-- Enable it when creating a new table
CREATE TABLE silver.orders (
order_id BIGINT,
customer_id BIGINT,
amount DECIMAL(10,2),
status STRING,
updated_at TIMESTAMP
)
TBLPROPERTIES (delta.enableChangeDataFeed = true);
-- Enable it on an existing table
ALTER TABLE silver.orders
SET TBLPROPERTIES (delta.enableChangeDataFeed = true);
-- Enable it by default across the whole workspace
SET spark.databricks.delta.properties.defaults.enableChangeDataFeed = true;Data read via CDF automatically includes three metadata columns. The most important one is _change_type, which indicates the kind of change.
| _change_type | Meaning | Operations that produce it |
|---|---|---|
| insert | A new row was inserted | INSERT, MERGE (NOT MATCHED THEN INSERT) |
| update_preimage | The state of the row before the update | UPDATE, MERGE (MATCHED THEN UPDATE) |
| update_postimage | The state of the row after the update | UPDATE, MERGE (MATCHED THEN UPDATE) |
| delete | The row was deleted | DELETE, MERGE (MATCHED THEN DELETE) |
For UPDATEs, both a preimage (before) and a postimage (after) row are recorded. This ability to trace exactly "what changed into what" is CDF's strength. Two additional metadata columns are also added: _commit_version (the Delta version number) and _commit_timestamp (the commit time).
-- Read changes over a range of versions
SELECT * FROM table_changes('silver.orders', 5, 10);
-- Read changes over a range of timestamps
SELECT * FROM table_changes('silver.orders', '2026-03-01', '2026-03-27');
-- Filter to a specific _change_type
SELECT * FROM table_changes('silver.orders', 5)
WHERE _change_type IN ('insert', 'update_postimage');# Start from a given version
cdf_stream = (spark.readStream
.format("delta")
.option("readChangeFeed", "true")
.option("startingVersion", 5)
.table("silver.orders")
)
# Start from a given timestamp
cdf_stream = (spark.readStream
.format("delta")
.option("readChangeFeed", "true")
.option("startingTimestamp", "2026-03-01")
.table("silver.orders")
)The most common use of CDF is incremental processing between Silver and Gold. Instead of fully rebuilding the Gold aggregate table every run, you fetch only the changes via CDF and apply them with MERGE.
def update_gold(batch_df, batch_id):
updates = batch_df.filter(
"_change_type IN ('insert', 'update_postimage')"
)
deletes = batch_df.filter("_change_type = 'delete'")
updates.createOrReplaceTempView("updates")
deletes.createOrReplaceTempView("deletes")
# UPSERT: apply inserts and the post-update state
spark.sql("""
MERGE INTO gold.order_summary t
USING updates s ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
# DELETE: remove deleted rows from Gold as well
spark.sql("""
MERGE INTO gold.order_summary t
USING deletes s ON t.order_id = s.order_id
WHEN MATCHED THEN DELETE
""")
(spark.readStream
.format("delta")
.option("readChangeFeed", "true")
.table("silver.orders")
.writeStream
.foreachBatch(update_gold)
.option("checkpointLocation", "/checkpoint/gold_orders")
.trigger(availableNow=True)
.start()
)trigger(availableNow=True) runs the stream in a batch-like fashion, processing all available CDF data and then stopping the stream automatically. It pairs well with scheduled jobs.
CDF is also useful for incremental data integration with external systems. Sending only the changes instead of resending the full dataset dramatically reduces network and processing costs.
Lakeflow Spark Declarative Pipelines APPLY CHANGES INTO is conceptually similar to CDF but lives at a different layer. CDF is a change-recording feature on the Delta Table side, while APPLY CHANGES INTO is a CDC-ingestion syntax on the Lakeflow Spark Declarative Pipelines pipeline side.
| Comparison axis | Change Data Feed | Lakeflow Spark Declarative Pipelines APPLY CHANGES INTO |
|---|---|---|
| Role | Records and exposes changes to a Delta Table | Applies changes from a CDC source into a Lakeflow Spark Declarative Pipelines table |
| How to enable | Table property | Lakeflow Spark Declarative Pipelines pipeline definition (SQL/Python) |
| Key specification | Not required (every row's changes are recorded) | Primary key specified via the KEYS clause |
| Sequencing | Ordered automatically by _commit_version | Ordering column specified via the SEQUENCE BY clause |
| SCD Type 2 | User implements the logic | Managed automatically with STORED AS SCD TYPE 2 |
-- Lakeflow Spark Declarative Pipelines APPLY CHANGES INTO example
APPLY CHANGES INTO LIVE.silver_orders
FROM STREAM(LIVE.bronze_orders_cdc)
KEYS (order_id)
SEQUENCE BY updated_at
COLUMNS * EXCEPT (_rescued_data)
STORED AS SCD TYPE 1;CDF data is stored in the Delta Table's _change_data directory. Running VACUUM also removes CDF data that falls outside the retention window.
-- Run VACUUM (7-day retention)
VACUUM silver.orders RETAIN 168 HOURS;
-- Use a longer retention period to allow for downstream pipeline lag
ALTER TABLE silver.orders
SET TBLPROPERTIES (
'delta.deletedFileRetentionDuration' = 'interval 30 days'
);Data Engineer Professional
Question 1
CDF is enabled on the Silver orders table. A record's status is updated from 'pending' to 'shipped'. What rows will the data read from CDF contain?
Correct answer: A
For an UPDATE operation, CDF records two rows: update_preimage (the state before) and update_postimage (the state after). This lets you fully trace what changed into what. There is no plain 'update' type, and CDF uses a preimage/postimage pair rather than a delete/insert combination.
What is the difference between CDF and Structured Streaming?
Change Data Feed (CDF) is a feature that automatically records changes to a Delta Table, exposing the results of INSERT/UPDATE/DELETE operations together with the _change_type, _commit_version, and _commit_timestamp metadata columns. Structured Streaming is Spark's streaming framework and is one of several ways to consume CDF data. Think of CDF as the mechanism that records changes, and Streaming as one way to read them.
Does enabling CDF increase storage costs?
Yes, slightly. When UPDATE or DELETE runs on a CDF-enabled table, the before/after row data is stored separately under the _change_data directory. Tables that only see INSERTs incur almost no additional cost. VACUUM can clean up old CDF data, but you must keep the retention window that downstream pipelines depend on.
How does CDF show up on the exam?
It is especially frequent on Data Engineer Professional. Common topics include how to enable CDF (table property), reading via the readChangeFeed option, the meaning of each _change_type value (insert/update_preimage/update_postimage/delete), and patterns for applying changes incrementally to downstream tables. Batch reads via the table_changes() function are also important.
Practice with certification-focused question sets
Try free questionsNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
Databricks Certifications: All 7 Exams, Difficulty & Study Plan (2026)
Complete guide to all 7 Databricks certifications — Data Eng...
Databricks Exam Difficulty Ranking: All 7 Certs Compared (2026)
Every Databricks certification ranked by difficulty, with st...
Databricks Study Guide: Fastest Pass Route & Time Estimates (2026)
How to pass Databricks certifications efficiently. Official ...
Databricks Data Engineer Associate: Complete Guide (2026)
Domain-by-domain breakdown of the Databricks Certified Data ...
Databricks Data Engineer Professional: Complete Guide (2026)
Tactics for the Databricks Certified Data Engineer Professio...