Create Your First Delta Table

Create your first Delta table in Databricks — hands-on steps, troubleshooting, and what to study next.

Focus: create your first delta table

Sponsored

You've built DataFrames, run transformations, and queried data in notebooks — but every time you restart a cluster, that work vanishes. Your data pipeline currently ends in a dead end: results exist only in memory, not as a durable, queryable asset your team can trust. The solution is Delta Lake, and the first step is learning how to create your first Delta table — the foundation of every reliable data pipeline on Databricks. In this lesson, you'll move from ephemeral DataFrames to persistent, versioned tables that support ACID transactions, time travel, and schema evolution.

The problem this lesson solves

Imagine you've spent hours cleaning and transforming a dataset, but when you try to share your results with a colleague, they can't see them. Or worse, the next day your pipeline fails because an upstream file changed format without notice. These are classic symptoms of working with raw files or in-memory data without a governed storage layer.

Raw Parquet or CSV files on cloud storage have no transaction support, no schema enforcement, and no versioning. If two jobs write to the same directory concurrently, you can corrupt your data. Delta Lake solves these problems by adding a transaction log and ACID guarantees on top of your existing storage. Creating your first Delta table is the single action that turns a collection of files into a reliable, queryable dataset.

Think of a Delta table as a database table that lives on your cloud storage — it's not a separate service, just a directory with a special _delta_log folder that tracks every change.

Core concept / mental model

The fastest way to grasp Delta tables is by analogy: a Delta table is like a bank ledger. Every transaction (insert, update, delete) is recorded in a log before the data changes. This log ensures that all reads see a consistent snapshot, even if multiple writers are active. If something goes wrong, you can roll back to a previous state — exactly like reviewing a bank statement.

Here are the key components you'll work with:

  • Table location: A directory on cloud storage (e.g., dbfs:/mnt/delta/events).
  • Data files: Parquet files that store the actual rows.
  • Transaction log: A _delta_log subdirectory containing JSON files — each file is a commit that describes what changed.
  • Table metadata: Schema, partitioning, and configuration stored in the log.

Delta tables support standard SQL and DataFrame operations, so you don't need to learn a new language — you just wrap your existing Spark code with the DELTA format.

How it works step by step

Creating a Delta table from a DataFrame is a three-step process:

  1. Load your source data into a Spark DataFrame using any of Databricks' connectors (Parquet, CSV, JSON, JDBC, or cloud storage).
  2. Write the DataFrame using .write.format("delta") and specify a path. This creates the table directory and initializes the transaction log.
  3. Register the table in the metastore (optional) with CREATE TABLE ... USING DELTA or df.write.saveAsTable(), so it appears in the Data Explorer and can be queried by name.

The critical point: the first write creates the schema and the table. Every subsequent write appends or overwrites data, and each write appends a new commit to the transaction log.

Hands-on walkthrough

Let's create your first Delta table in a Databricks notebook. We'll start with a small CSV dataset and work through the standard patterns.

1. Create a Delta table from a CSV

First, load a sample CSV from the Databricks datasets:

# Load sample data
df = spark.read.csv("/databricks-datasets/COVID/covid-19-data/us-counties.csv",
                    header=True, inferSchema=True)

# Write to a Delta table (this is step one — your first Delta table!)
df.write.format("delta").mode("overwrite").save("/mnt/delta/covid_us")  # Note: use DBFS root path in notebooks

If you run this, you'll see a message like Delta Lake updated 5 files in 0.89 seconds. Check the location with:

display(spark.sql("DESCRIBE EXTENDED delta.`/mnt/delta/covid_us`"))

You'll see the table schema, location, and format — all confirmed as Delta.

2. Register the table in the metastore

To make the table accessible by name across your workspace, register it:

# Register as a managed table in the default database
spark.sql("CREATE TABLE covid_us USING DELTA LOCATION '/mnt/delta/covid_us'")
# Or with saveAsTable (creates a managed table in the database)
df.write.saveAsTable("covid_us")

Now you can query it with SQL:

SELECT state, COUNT(*) FROM covid_us GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;

3. Append new data and verify time travel

Delta tables shine with updates. Let's append a few fake rows and then use time travel to see the original version:

# Append new data
from pyspark.sql import Row
new_rows = spark.createDataFrame([
    Row(date="2021-01-01", county="Test", state="XX", fips=999, cases=0, deaths=0)
])
new_rows.write.format("delta").mode("append").save("/mnt/delta/covid_us")

# Show table history
spark.sql("HISTORY covid_us").show(5, truncate=False)

# Query version 0 (original)
spark.sql("SELECT COUNT(*) FROM covid_us VERSION AS OF 0").show()

You should see counts change, and the history shows two versions.

Compare options / when to choose what

When creating a Delta table, you have several choices — especially around table type and write modes. Here's a quick guide:

Option Best For Notes
Managed table (saveAsTable) Databricks-owned tables in a catalog Files are deleted when the table is dropped; easier to manage
External table (LOCATION with USING DELTA) Tables with existing data on cloud storage Drops only the metadata, not the files
.mode("overwrite") Full refresh — replace entire table Works atomically in Delta; replaces the whole directory
.mode("append") Incremental loads — new events daily Adds new files without disturbing existing data
MERGE (upsert) Slowly changing dimensions or deduplication Most flexible; updates/inserts/deletes in one operation

For most ETL pipelines, start with external tables if data already lives in cloud storage, otherwise use managed tables. Use append for log-style data and merge for transactional changes.

Troubleshooting & edge cases

"Path does not exist" when reading a Delta table

Ensure the path is correct and permissions allow access. In Databricks, use dbfs:/ for DBFS paths, or the direct cloud path (e.g., s3://). Check with dbutils.fs.ls().

Schema mismatch when appending

If the new DataFrame has a different column order or data type, the write may fail. Use .option("mergeSchema", "true") to allow schema evolution:

df_new.write.format("delta").option("mergeSchema", "true").mode("append").save("/mnt/delta/covid_us")

"Cannot resolve 'column'" in SQL after saving as table

Your query uses a column that doesn't exist — check the schema with DESCRIBE covid_us.

Table appears empty after overwrite

Did you use mode("overwrite")? It replaces the entire table — if you intended to update a few rows, use MERGE.

Overwriting a table while other jobs are reading

Delta's optimistic concurrency control will prevent lost updates — you may get a conflict error. Retry the operation or use MERGE to avoid conflicts.

What you learned & what's next

You've created your first Delta table, registered it, appended data, and used time travel — that's the ACID foundation. You can explain how a Delta table stores data in Parquet plus a transaction log, and you can confidently choose between managed/external tables and write modes.

Next up: In the next lesson, you'll learn to read and transform data from your Delta table — including how to handle schema evolution and optimize performance with Z-order and partitioning. Now that you have a durable asset, you can build streaming and batch pipelines that everyone can trust.

Practice saving the same DataFrame to managed and external tables, then drop one and observe the behavior — it's the fastest way to internalize the difference.

Practice recap

Try creating a Delta table from a new dataset (e.g., /databricks-datasets/nyctaxi). Append a few rows, run HISTORY, then query a previous version. Also create an external table using CREATE TABLE ... USING DELTA LOCATION and confirm the files remain after dropping the table. This will solidify the difference between managed and external tables.

Common mistakes

  • Using mode("overwrite") for every write — erases existing data when you only meant to append.
  • Forgetting to register the table in the metastore — then you can't query it by name in SQL.
  • Writing to a path that is already a Parquet table — Delta will fail or overwrite unexpectedly; use a new path or ANALYZE TABLE.
  • Not handling schema evolution — appending data with different columns fails unless you set mergeSchema.
  • Querying a table without refreshing the metastore after creating it from SQL — use REFRESH TABLE if needed.

Variations

  1. Use CREATE OR REPLACE TABLE for idempotent table creation.
  2. Use Python's DeltaTable API (delta.tables.DeltaTable) for programmatic management like upserts.
  3. Use OPTIMIZE and ZORDER after table creation to improve query performance.

Real-world use cases

  • Daily COVID-19 county data: append new data daily, time-travel to historical versions for trend analysis.
  • Clickstream events: stream raw events into a Delta table with MERGE to deduplicate and maintain a clean dataset.
  • Financial transactions: use ACID guarantees to safely upsert customer balances and audit changes with the transaction log.

Key takeaways

  • A Delta table = Parquet files + transaction log, providing ACID, versioning, and schema evolution.
  • Create a table with .write.format("delta") or SQL CREATE TABLE USING DELTA; register it in the metastore for SQL access.
  • Append vs. overwrite: use mode("append") for incremental loads, overwrite for full refresh — never casually.
  • Time travel lets you query previous versions using VERSION AS OF — invaluable for debugging and reproducibility.
  • Managed tables are easy for Databricks-owned data; external tables preserve files when you drop metadata.
  • Troubleshoot schema mismatches with mergeSchema and check file paths with dbutils.fs.ls().

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.