Develop Lakeflow Spark Declarative Pipelines (formerly Delta Live Tables) on Databricks. Use when building batch or streaming data pipelines with Python or SQL, including Auto CDC from event streams or periodic complete snapshots. Invoke BEFORE starting implementation.
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
FIRST: Use the parent databricks-core skill for CLI basics, authentication, profile selection, and data discovery commands.
SDP, LDP, Lakeflow Declarative Pipelines, and DLT (former name) all refer to the same product.
Use this tree to choose the dataset type first, then layer on applicable features. Multiple features can apply to the same dataset — e.g., a Streaming Table can use Auto Loader for ingestion, Append Flows for fan-in, and Expectations for data quality.
User request → What kind of output?
├── Intermediate/reusable logic (not persisted) → Temporary View (default)
│ ├── Preprocessing/filtering before Auto CDC → Temporary View feeding CDC flow
│ ├── Shared intermediate streaming logic reused by multiple downstream tables
│ ├── Pipeline-private helper logic (not published to catalog)
│ ├── Expensive intermediate that is reused across refreshes → Private ST/MV (materialized but pipeline-scoped)
│ └── Published to UC for external queries → Persistent View (SQL only)
├── Persisted dataset
│ ├── Source is a periodic complete snapshot that must be diffed by key → Streaming Table + Auto CDC FROM SNAPSHOT
│ ├── Source is streaming/incremental/continuously growing → Streaming Table
│ │ ├── File ingestion (cloud storage, Volumes) → Auto Loader
│ │ ├── Message bus (Kafka, Kinesis, Pub/Sub, Pulsar, Event Hubs) → streaming source read
│ │ ├── Existing streaming/Delta table → streaming read from table
│ │ ├── CDC / upserts / track changes / keep latest per key / SCD Type 1 or 2 → Auto CDC (only when this pipeline owns the target; merge/upsert into an existing/external table → ForEachBatch Sink)
│ │ ├── Multiple sources into one table → Append Flows (NOT union)
│ │ ├── Historical backfill + live stream → one-time Append Flow + regular flow
│ │ └── Windowed aggregation with watermark → stateful streaming
│ └── Source is batch/historical/full scan → Materialized View
│ ├── Aggregation/join across full dataset (GROUP BY, SUM, COUNT, etc.)
│ ├── Gold layer aggregation from streaming table → MV with batch read (spark.read / no STREAM)
│ ├── JDBC/Federation/external batch sources
│ └── Small static file load (reference data, no streaming read)
├── Output to a target the pipeline does NOT own (external / pre-existing / managed elsewhere) → Sink (Python only, even if the user asked for SQL)
│ ├── External or pre-existing Delta table → Sink with format="delta"
│ ├── Kafka / Event Hubs → Sink with format="kafka" + @dp.append_flow(target="sink_name")
│ ├── Custom destination not natively supported → Sink with custom format
│ ├── Custom merge/upsert into an existing/external table → ForEachBatch Sink, NOT Auto CDC
│ └── Multiple destinations per batch → ForEachBatch Sink
└── Data quality constraints → Expectations (on any dataset type)__START_AT / __END_AT, not invented names. Current rows: __END_AT IS NULL; point-in-time: __START_AT <= t AND (__END_AT > t OR __END_AT IS NULL). Read scd-2-querying.schemaHints match the actual file schema.STREAM). Streaming tables are append-only and don't recompute aggregates when source rows change.Cannot create streaming table from batch query: The streaming table reads in batch. Use FROM STREAM read_files(...) / FROM STREAM(table).databricks fs on Volumes: The CLI needs the dbfs: prefix, e.g. databricks fs ls dbfs:/Volumes/<catalog>/<schema>/<volume>/<path>.Pipelines publish to the default catalog/schema in their settings.
catalog.schema.table publishes a pipeline-owned dataset elsewhere; no sink needed. External, pre-existing, or separately managed targets require a Python sink, even if the user requested SQL.USE CATALOG / USE SCHEMA changes the defaults for subsequent definitions in the same SQL file.LIVE is deprecated and ignored in default publishing mode.MANDATORY: Before implementing, editing, or suggesting feature code, read its linked reference and these required companions:
| Feature | Python | SQL |
|---|---|---|
| Streaming tables; explicit targets; append and one-time backfill flows; skip upstream change commits | Python | SQL |
| Materialized views; liquid clustering (prefer auto), partitioning, table properties, explicit schemas, generated columns, row filters and column masks (Public Preview), private datasets | Python | SQL |
| Temporary views | Python | SQL |
| Persistent UC views | Unsupported | SQL |
| Delta/Kafka/Event Hubs/custom sinks | Python | Unsupported |
| ForEachBatch sinks | Python | Unsupported |
| Auto CDC from a stream or periodic snapshots | Python | SQL |
| Expectations: warn, drop, fail; individual or multiple constraints | Python | SQL |
| Auto Loader | Python | SQL |
Topics covering both languages:
spark.read.table("name") / SELECT ... FROM name; streaming reads: spark.readStream.table("name") / SELECT ... FROM STREAM(name).spark.readStream.format("kinesis" | "pubsub" | "pulsar"); SQL uses STREAM read_kinesis(...), STREAM read_pubsub(...), or STREAM read_pulsar(...).spark.read.format("postgresql") etc. and SQL references the federation catalog.spark.read.format(...).load(...) / read_files(...) without STREAM.spark.read[Stream].format("custom").from pyspark import pipelines as dp and spark.read[Stream].table for Python.If you see any of the following in user code, it is the legacy DLT syntax — always migrate to the modern form, do not extend it. Read references/dlt-migration.md before suggesting changes so the conversion is correct (especially around apply_changes → create_auto_cdc_flow semantics and partition_cols → cluster_by).
| If you see… | …it's DLT. Migrate to |
|---|---|
import dlt | from pyspark import pipelines as dp |
@dlt.table(...), @dlt.append_flow(...), @dlt.expect* | Same decorator name on dp.* (e.g. @dp.table, @dp.expect_or_drop). |
@dlt.view(...) (or @dp.view(...) if present in older code) | @dp.temporary_view(...) — the modern API has no view decorator, only temporary_view. |
dlt.read("name") / dlt.read_stream("name") | spark.read.table("name") / spark.readStream.table("name") |
dp.read(...) / dp.read_stream(...) | Also legacy — use spark.read.table(...) / spark.readStream.table(...). |
dlt.apply_changes(...) / dp.apply_changes(...) | dp.create_auto_cdc_flow(...). sequence_by accepts a column name (string) or col(...); stored_as_scd_type is integer 2 for Type 2 or string "1" for Type 1. |
dlt.apply_changes_from_snapshot(...) | dp.create_auto_cdc_from_snapshot_flow(...) |
dlt.create_streaming_table(...) | dp.create_streaming_table(...) |
LIVE.<name> prefix in SQL | Bare name (SELECT FROM name for batch, SELECT FROM STREAM(name) for streaming). LIVE. will error in modern pipelines. |
CREATE LIVE TABLE / CREATE STREAMING LIVE TABLE | CREATE OR REFRESH MATERIALIZED VIEW / CREATE OR REFRESH STREAMING TABLE. |
CREATE TEMPORARY LIVE VIEW (a.k.a. CREATE LIVE VIEW) | CREATE TEMPORARY VIEW. Exception: CREATE TEMPORARY VIEW does NOT support CONSTRAINT clauses for expectations — for the rare case where you need expectations on a temp view, CREATE LIVE VIEW is retained. See temporary-view-sql.md and expectations-sql.md. |
APPLY CHANGES INTO ... FROM STREAM ... (SQL) | AUTO CDC INTO ... FROM STREAM ... |
partition_cols=[...] / PARTITIONED BY (...) + ZORDER | cluster_by=[...] / CLUSTER BY (...) (Liquid Clustering). |
input_file_name() | _metadata.file_path (SQL) / F.col("_metadata.file_path") (Python). |
target=... parameter on create_streaming_table / pipeline config | schema=... |
databricks.yml → 1-project-initialization-with-dab. Default for production-bound work.resources/<name>.pipeline.yml; see Workflow B in the same reference.src/ or transformations/. In Gold, keep the dimensions consumers filter by (e.g., every dashboard filter).databricks bundle deploy; deploy before any run, dry run, or selective refresh. Sequence: databricks bundle validate, databricks bundle deploy -t dev, databricks bundle run <pipeline_name> -t dev.databricks workspace import-dir ... --overwrite after every change, then databricks pipelines start-update.INITIALIZING for a few minutes on cold start; don't cancel it.--validate-only) is a faster way to confirm the correctness of the pipeline code.databricks/databricks-agent-skills
11e8e82
Also appears in
last in sync Oct 8, 2026
since Oct 2, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.