How to Create a Delta Table with PySpark in the Lakehouse
Saving transformed data into a Delta table is the most practical way to make it available for analysis in Microsoft Fabric. With just a few lines of PySpark, you can create a managed Delta table from a Spark DataFrame, right inside a notebook and without leaving the Lakehouse. Once created, the table is immediately ready for SQL queries and Power BI reports — which is why knowing how to create a Delta table in the Lakehouse is the foundation of almost every data pipeline in Fabric.
Prerequisites
- An active Microsoft Fabric capacity (free trial, Premium, or an F SKU).
- A Lakehouse already created in your workspace.
- Contributor permissions (or higher) on that workspace, required to write tables.
- Basic Python knowledge. You don't need to install or configure Spark: it comes ready in Fabric.
Step 1: Create a notebook and attach the Lakehouse
Open your Lakehouse and select Open notebook > New notebook. Alternatively, create a notebook from the Data Engineering experience and, in the Explorer pane on the left, use Add lakehouse to attach it. This step is essential: the attached Lakehouse becomes the default destination for the tables you write. Without an attached Lakehouse, Spark doesn't know where to save and the write fails.
Step 2: Load the data into a DataFrame
To create a table you first need a Spark DataFrame. In this example we read a CSV file stored in the Files section of the Lakehouse, but the source can be anything else: an existing table, the result of a transformation, or a query. The header and inferSchema options help Spark correctly interpret the header row and the data types.
df = (spark.read
.option("header", "true")
.option("inferSchema", "true")
.csv("Files/sales/sales.csv"))
df.printSchema()
display(df)
The display(df) command shows an interactive preview. Use it to confirm the columns and types look as expected before moving on.
Step 3: Write the DataFrame as a Delta table
With the data in the DataFrame, just write it to the Tables section in Delta format. The saveAsTable() method creates a managed table: Fabric writes the Parquet files and registers the table in the metastore in a single step.
(df.write
.format("delta")
.mode("overwrite")
.saveAsTable("sales"))
The overwrite mode replaces the table if it already exists; switch to append when you want to add rows to an existing table. One important detail to avoid errors: the Fabric Lakehouse only supports managed tables. Don't use CREATE TABLE ... LOCATION and don't create subfolders inside Tables, because the Lakehouse won't recognize them as tables and will show them as "Unidentified".
Step 4: Optimize the write with V-Order (optional)
Fabric can lay out the Parquet files for faster reads and smaller storage. If you want that gain, enable V-Order and Optimize Write in a cell at the start of the notebook, before writing:
spark.conf.set("spark.sql.parquet.vorder.enabled", "true")
spark.conf.set("spark.microsoft.delta.optimizeWrite.enabled", "true")
These settings reduce the number of files generated and improve compression, without requiring any change to the write code from Step 3.
Verify the result
Confirm the table was created in two ways. First, in the Explorer pane, expand the Tables folder, click the ellipsis (...), and choose Refresh: the sales table should appear with the Delta table icon. Then validate in code by reading the table back:
spark.sql("SELECT COUNT(*) AS total FROM sales").show()
# or directly from the path in the Tables section
spark.read.format("delta").load("Tables/sales").show(5)
If the row count matches what you expected, you're all set. The table is also immediately available in the Lakehouse SQL analytics endpoint, where you can query it with T-SQL.
Conclusion
With the Delta format and the saveAsTable() method, you turned a DataFrame into a managed, analysis-ready table in seconds — the pattern you'll repeat in practically every Lakehouse pipeline. As next steps, try scheduling this write inside a Fabric pipeline or using append mode for incremental loads. One question to think about before you go: how will you make sure a new run doesn't create duplicate rows in your table?