Create a Live Table with Delta Live Tables
Create a live table with Delta Live Tables — Databricks. Learn how to define and manage live tables, run a pipeline, and follow best practices in this hands-on tutorial.
Focus: create a live table with delta live tables
You've built batch pipelines that work — until the schema changes, the data lands late, or your boss asks for a dashboard that reflects the last five minutes. Manually orchestrating Spark jobs and praying the data is fresh is a recipe for late nights. Delta Live Tables (DLT) on Databricks removes the pain: you declare your datasets as live tables, and the platform builds, runs, and maintains the entire pipeline for you. In this lesson, you'll learn how to create a live table with Delta Live Tables, run a pipeline, and adopt best practices that turn brittle ETL into a self-healing, production-grade system.
The problem this lesson solves
Classic ETL pipelines are fragile. You write a notebook, schedule a job, and hope the upstream data is there. When something breaks, you debug Spark logs at 2 a.m. And even when it works, your data can be stale, duplicated, or missing quality checks.
Delta Live Tables solves these problems by introducing a declarative model: you define what each table should be, not how to build it. A live table is a dataset that DLT manages automatically — it tracks dependencies, computes the data in the right order, and refreshes incrementally when new data arrives. Think of DLT as a pipeline-as-code layer on top of Delta Lake: it handles orchestration, retries, and monitoring so you can focus on the logic.
The specific pain points DLT addresses:
- Orchestration complexity — no more chaining notebooks or managing Airflow DAGs.
- Schema drift — DLT can enforce, evolve, or quarantine schema changes automatically.
- Data quality — built-in constraints and expectation checks fail fast or quarantine bad rows.
- Incremental processing — you get streaming and batch in one unified API; no separate code paths.
- Infrastructure management — DLT provisions and scales the underlying compute for you.
Pro tip: If you've ever been burned by a silent schema change breaking a downstream table, DLT's schema evolution and expectations will feel like a superpower.
Core concept / mental model
Imagine you're building a house. A traditional pipeline is like hand-carrying each brick, mixing cement, and checking the walls yourself every time. DLT is like having a general contractor: you hand them a blueprint (your Python or SQL code), and they manage the crew, the materials, and the inspections. You only need to review the final structure.
In DLT, the blueprint is a set of live table declarations — functions or SQL statements that define a dataset. Each live table is a Node in a directed acyclic graph (DAG). DLT reads your code, builds the DAG, then executes it in the correct order, parallelizing independent branches.
Key terms:
- Live table — a dataset managed by DLT; can be a view, a materialized view, or a streaming table.
- Pipeline — the execution unit that runs all your live tables, with associated compute and configuration.
- Expectations — data quality rules (like constraints) that DLT enforces.
- Target schema — the database where DLT writes your live tables (e.g.,
main.default).
Here's a mental picture of a DLT pipeline:
[Cloud Files / Kafka] → Bronze (raw, streaming) → Silver (clean, deduplicated) → Gold (aggregated)
Each stage is a live table. DLT manages the flow, and you only write the definitions.
How it works step by step
Creating a live table with Delta Live Tables follows a clear pattern — you define, then run. Here's the high-level flow:
- Author DLT code — in a notebook or file, import
dltand declare at least one@dlt.tabledecorated function (or useCREATE LIVE TABLEin SQL). - Create a pipeline — in the Databricks UI, click Delta Live Tables → Create Pipeline, name it, and attach your notebook or file path.
- Configure compute and target — choose a serverless or classic compute profile, and set the target schema (e.g.,
main.default). - Run the pipeline — start a triggered or continuous run. DLT builds the DAG and executes all tables.
- Monitor and iterate — check the pipeline UI for metrics, data quality, and lineage. Adjust code and rerun.
The key is that DLT tracks metadata about each table: the version, the data, and the dependencies. When you rerun, DLT only recomputes what changed, using incremental processing where possible.
Declarative vs. imperative
In a traditional notebook, you write imperative code: df = spark.read... and df.write.... With DLT, you write declarative code: `@dlt.table` tells DLT, "this is a table; here's its definition." DLT decides when and how to compute it.
The role of expectations
You can attach expectations to a live table to enforce data quality. For example, you can require that id is not null, or that amount is positive. If a row violates an expectation, you can warn, drop, or fail the pipeline. This is a game-changer for production pipelines.
Hands-on walkthrough
Let's get practical. In this example, we'll create a simple DLT pipeline with two live tables: a raw (bronze) table and a cleaned (silver) table. We'll use Python — the same pattern applies to SQL.
Step 1: Create a notebook and set up your code
In your Databricks workspace, create a new notebook (use a cluster-independent Python notebook — DLT manages the cluster). Paste the following code in a cell:
import dlt
from pyspark.sql.functions import col, current_timestamp
# Define a live table that reads from a file path (e.g., a CSV landing zone)
@dlt.table(
comment="Raw sales data from external system",
table_properties={
"quality": "bronze"
}
)
def raw_sales():
return (
spark.read.format("cloudFiles")
.option("cloudFiles.format", "csv")
.load("/databricks-datasets/retail-org/sales_orders_csv")
)
# Define a live table that cleans the raw data
@dlt.table(
comment="Cleaned sales data with data quality checks",
table_properties={
"quality": "silver"
}
)
@dlt.expect("valid_quantity", "quantity > 0")
@dlt.expect_or_drop("valid_customer_id", "customer_id IS NOT NULL")
def cleaned_sales():
return (
dlt.read("raw_sales")
.select(
col("order_id"),
col("customer_id"),
col("amount"),
col("quantity"),
current_timestamp().alias("ingested_at")
)
)
Step 2: Create and run the pipeline
- In the sidebar, click Delta Live Tables.
- Click Create Pipeline.
- Name it
sales_pipeline. - In Notebook Libraries, add your notebook.
- In Target schema, enter
main.default(or a database you have access to). - For Compute, choose the Serverless option (if available) or leave defaults.
- Click Create and then Start to run the pipeline.
Expected output: The pipeline will show two tables, raw_sales and cleaned_sales, with Created or Updated status. You'll see metrics like rows written and data quality pass/fail counts.
Step 3: Query your live tables
After the run, go to the SQL Warehouse or a SQL notebook and run:
SELECT * FROM main.default.cleaned_sales;
You'll see the cleaned data with the ingested_at timestamp. The raw_sales table is still there for lineage and debugging.
Step 4: Modify and rerun (CI/CD ready)
Change a business rule — for example, add a new column transformation — then rerun the pipeline. DLT will recompute only the affected tables and preserve downstream data if possible. This is the power of declarative pipelines.
Compare options / when to choose what
You might wonder: when should I use DLT versus a classic notebook job or Spark structured streaming? Here's a quick comparison:
| Approach | Orchestration | Incremental support | Data quality | Complexity | Best for |
|---|---|---|---|---|---|
| Classic notebook + job | Manual (need Airflow or similar) | DIY with partitionBy or streaming |
Manual checks | Medium | Ad-hoc analysis, simple batch jobs |
| Spark structured streaming | Manual | Built-in | Manual | High | Real-time stream processing as part of a larger app |
| Delta Live Tables | Automatic (DAG) | Built-in (streaming + batch) | Built-in (expectations) | Low | Production ELT with quality gates, multiple stages |
When to choose DLT:
- You have multiple tables with dependencies.
- You need incremental refresh on a schedule.
- You want built-in data quality to prevent bad data from reaching analysts.
- You want to reduce orchestration overhead.
When to avoid DLT:
- You need to integrate with a non-Databricks orchestrator for cross-platform dependencies.
- You're doing heavy custom Spark tuning that the DLT abstraction might hide.
- You only have a one-off query — a simple notebook is fine.
Variations
- SQL live tables — you can use
CREATE LIVE TABLEandCREATE STREAMING LIVE TABLEin SQL notebooks, which is great for SQL-savvy teams. - Views vs. materialized views — DLT offers
@dlt.view(always recomputed on refresh) vs.@dlt.table(persisted). Choosing depends on whether you need to persist intermediate results. - Auto Loader vs.
spark.read— for incremental file ingestion, Auto Loader (via.format("cloudFiles")) is the recommended option, as it can detect new files withoutfrom_timestamptricks.
Troubleshooting & edge cases
DLT is robust, but you will hit issues. Here are common ones and how to fix them:
- Pipeline fails with 'Table not found' — Check your dependencies. Did you use
dlt.read("table_name")with the correct name? DLT uses the function name or thenameparameter in the decorator. - Schema mismatch on a re-run — If you change a column's type, DLT might fail or need manual refresh. Use schema evolution settings in the pipeline, or handle with
@dlt.expect_or_dropto filter bad rows. - Incremental update returns no new data — For streaming tables, ensure your source is actually receiving new events. For Auto Loader, verify that new files are being written to the ingestion path.
- Expectation violations with
expect_or_drop— Rows are silently dropped. Check the metrics to see if you're losing too much data; adjust the expectation toexpect(warn) first. - Compute failure due to out-of-memory — Increase the cluster size or use Serverless compute. DLT's autoscaling helps, but check your
spark.sql.shuffle.partitionsfor large shuffles.
Pro tip: Always run a pipeline with a
CREATE(full refresh) first using a small sample dataset to validate logic before enabling incremental updates.
What you learned & what's next
You've learned how to create a live table with Delta Live Tables: you understand the declarative model, you've written a Python DLT pipeline with expectations, and you've run it to produce live tables in your target schema. You also know when DLT beats classic pipelines and how to troubleshoot common pitfalls.
Now that you can define live tables, the next logical step is to manage table dependencies and add more sophisticated data quality checks — expect to build multi-stage bronze/silver/gold pipelines with incremental refreshes and expectation policies that keep your Lakehouse trustworthy.
Keep experimenting: try adding a third table, using Auto Loader with JSON files, or setting up a continuous pipeline for real-time tables.
Practice recap
Create a new DLT pipeline that reads from a sample dataset, defines a bronze raw table, a silver cleaned table with expectations, and a gold aggregate table. Run it, then query the target schema to verify quality. Experiment with changing an expectation to expect (warn) instead of expect_or_drop and observe the metrics.
Common mistakes
- Forgetting to import
dltin a Python notebook, leading toNameError: name 'dlt' is not defined - Using
spark.readinstead ofdlt.readto reference another live table, breaking dependency tracking - Defining a live table as a simple function that doesn't return a DataFrame — DLT will fail to infer the schema
- Not setting a target schema, so tables are created in a default location you can't easily query
Variations
- SQL DLT: Use
CREATE LIVE TABLE table_name AS SELECT ...to define tables without Python. - Views vs. tables: Use
@dlt.viewwhen you don't need to persist intermediate results. - Streaming tables: Use
@dlt.tablewith.readStreamor Auto Loader for continuously updated live tables.
Real-world use cases
- Building a multi-stage ELT pipeline that ingests raw logs into a bronze table, cleans them into a silver table, and computes daily aggregates for dashboards.
- Implementing a continuous pipeline that reads from Apache Kafka and updates a real-time live table for fraud detection alerts.
- Creating an incremental data pipeline with Auto Loader that ingests new CSV files from cloud storage as they land, with schema evolution and quality checks.
Key takeaways
- Delta Live Tables lets you define datasets declaratively, and the platform orchestrates the pipeline for you.
- Use
@dlt.tableand@dlt.expectto build live tables with built-in data quality. - DLT automatically builds a DAG of dependencies and supports incremental processing.
- Compare DLT vs. classic notebooks: DLT reduces orchestration, but classic notebooks are fine for ad-hoc work.
- Troubleshoot by checking dependency names, schema evolution, and expectation strictness.
- Next up: manage table dependencies and enforce more advanced data quality policies.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.