What is a Delta table?#

A Delta table is the standard way Microsoft Fabric stores tabular data. Underneath, it is a set of Parquet data files plus a file-based transaction log, and that log is what makes Delta special: it gives the table ACID transactions, schema enforcement, and time travel over those Parquet files [S1]. In plain terms, this means writes either fully succeed or fully fail (no half-written tables), the table rejects data that doesn't match its expected columns and types, and you can look back at earlier versions of the table's history rather than only ever seeing the latest state.

Delta isn't a Fabric-only invention layered on top of the platform — it's the open format that Fabric has standardized on everywhere. Every Fabric data item, including lakehouses and warehouses, automatically persists its tabular data in OneLake using the open Delta Parquet format, no matter which engine wrote the data [S5]. That's a big deal for a beginner to internalize: whether you loaded data with Spark, Data Factory, or T-SQL, it lands in the same open format underneath, which is why different engines can all read it.

Anatomy of a Delta table on OneLake

Where Delta tables show up#

Lakehouse. A lakehouse is a database built over the data lake holding files, folders, and tables; it's served by both the Spark engine and the SQL engine, and it gains ACID transaction support specifically because its tables use the open Delta format [S2]. Inside a lakehouse, storage is split into two areas: a managed Tables area reserved for Delta tables, and a Files area for unstructured or non-Delta data [S1]. When data lands in that managed Tables area, Fabric automatically validates that it's in Delta format, extracts column names, types, compression, and partitioning metadata, and registers the table in the metastore — so it's immediately queryable from Spark SQL or T-SQL with no manual CREATE TABLE step [S1]. Right now, Delta is the only format Fabric will auto-register this way [S1].

SQL analytics endpoint. Every lakehouse automatically provisions a read-only SQL analytics endpoint at creation, with no setup required, exposing the lakehouse's Delta tables through T-SQL [S3]. Only Delta tables surface through this endpoint — including Delta tables reached via OneLake shortcuts — so Parquet, CSV, or other formats must first be converted to Delta before they're queryable there [S1]. Whenever a Delta table is created or changed, the endpoint detects it and refreshes its own metadata (definitions, column types, statistics) automatically, with manual refresh also available; there's no separate import step [S3]. The endpoint is read-only: you can create views, inline table-valued functions, and procedures and manage object permissions through it, but you cannot modify the underlying data [S4].

Warehouse. Warehouse tables are also physically stored as Delta tables — Parquet files plus a transaction log — the same open format used everywhere else in Fabric, which lets engineers and business users share data without keeping separate copies [S4]. Warehouse data is automatically published to OneLake Files in Delta format too, so external engines and other Fabric workloads can read the same tables without an export job [S4]. You can load a warehouse several ways: the COPY INTO T-SQL command, Data Factory pipelines, Dataflows, direct Spark bulk writes to the Delta tables, or cross-database CTAS/INSERT...SELECT/SELECT INTO [S4].

Direct Lake for Power BI. Direct Lake is a semantic-model storage mode where the model reads Delta tables straight from OneLake, skipping both a data import and a live DirectQuery connection — giving import-like speed with DirectQuery-like freshness [S2] [S5]. It sits alongside the existing import and DirectQuery modes as a third option [S5].

Mirroring. Fabric Mirroring is a fully managed, serverless replication service that continuously brings data from external operational and analytical databases into OneLake, converting it into Parquet files in Delta Lake format — without you having to build or maintain ETL pipelines [S6].

A worked example#

Say a team loads a CSV of orders into a lakehouse's Files area with a Spark notebook, then writes it out as a managed table. Because the write targets the managed Tables area in Delta format, Fabric auto-detects the schema and registers the table in the metastore immediately [S1]. Minutes later, an analyst opens the SQL analytics endpoint and queries the same table with T-SQL — no import, because the endpoint refreshed its metadata as soon as the Delta table appeared [S3]. Meanwhile, a Power BI report built on a Direct Lake semantic model over that same table reads the Delta Parquet files directly from OneLake, so the report reflects the new data without a separate refresh-and-load cycle [S5]. One physical copy of the data, read by three different engines.

What goes wrong#

  • Expecting non-Delta formats to "just work." Parquet or CSV files sitting in the lakehouse Files area won't show up in the SQL analytics endpoint or get auto-registered in the metastore — only Delta tables in the managed Tables area do [S1].
  • Confusing the SQL analytics endpoint with a place to write data. It's read-only: you can create views, functions, and procedures and manage permissions, but you cannot modify the underlying data through it [S4].
  • Assuming a manual refresh is always required. The SQL analytics endpoint refreshes automatically when the underlying Delta table changes; manual refresh is an option, not a requirement [S3].
  • Mixing up Fabric Spark runtime settings. Write-optimization config keys are version-specific — for example, the Optimized Write setting changed key names between Runtime 1.2 (spark.microsoft.delta.optimizeWrite.enabled) and Runtime 1.3+ (spark.databricks.delta.optimizeWrite.enabled) [S7]. Copying a setting from an old notebook into a newer runtime without checking the current key name is a common source of "why didn't this apply" confusion.

AI-generated deep dive (beyond the verified knowledge base)#

The section below is AI-generated from model knowledge, not from verified Fabric Codex claims. It is believed factual; verify specifics against current documentation before relying on them.

Time travel you can actually try#

Because every write to a Delta table produces a new numbered version in the transaction log, you can query the table as it was at an earlier point. In Spark SQL this looks like:

sql
SELECT * FROM orders VERSION AS OF 12;
SELECT * FROM orders TIMESTAMP AS OF '2026-06-01';

The same idea works from a DataFrame read with the versionAsOf or timestampAsOf options. This is enormously useful for "what changed since yesterday?" debugging, reproducing a report from a known state, or comparing before/after a load. If a bad write slips through, RESTORE TABLE orders TO VERSION AS OF 11 rolls the table back — it does this by writing a new commit that re-points to the old files, so the mistake stays in history and is itself auditable.

One caution: time travel is not a backup. Old versions are only readable while their underlying Parquet files still exist, and maintenance operations that clean up unreferenced files (such as VACUUM) will eventually remove them. Treat time travel as a short-range convenience window, not an archive.

Reading the table's diary: DESCRIBE HISTORY#

Run DESCRIBE HISTORY orders and Delta returns one row per commit: the version number, timestamp, the operation performed (WRITE, MERGE, DELETE, OPTIMIZE, and so on), who or what ran it, and operation parameters such as whether a write was an append or an overwrite. This is the first place to look when a table "changed and nobody knows why" — the log already recorded the answer. It is also how you find the version number to use with VERSION AS OF.

Schema enforcement vs. schema evolution#

By default, Delta enforces the schema strictly: an append whose columns or types don't match is rejected rather than silently corrupting the table. When you intend to change the shape of the data, you opt in explicitly:

  • .option("mergeSchema", "true") on a write lets new columns be added to the table's schema while existing data is untouched (existing rows read as null for the new columns).
  • .option("overwriteSchema", "true") combined with an overwrite replaces the schema entirely — a much bigger hammer, appropriate only for deliberate table redesigns.

The habit to build early: never work around a schema error by casting data to "whatever the table wants" without understanding why the mismatch occurred. The enforcement error is Delta telling you that either your pipeline drifted or your table design needs a deliberate, opt-in evolution — and DESCRIBE HISTORY will show exactly when a schema change landed.