Medallion Architecture in Microsoft Fabric: 2026 Implementation Guide

Data Engineering
powerbiconsulting.com
Data Engineering18 min read

Medallion Architecture in Microsoft Fabric: 2026 Implementation Guide

Complete Bronze / Silver / Gold implementation for Microsoft Fabric with production PySpark, Delta partitioning strategy, CU cost model per layer, and CI/CD wrap-up. The 2026 answer to the medallion pattern in Fabric.

By the Power BI Consulting Team

Medallion architecture is the most cited design pattern for lakehouse platforms, and every Fabric implementation you inherit or build in 2026 will reference it. The problem is that the published guides tend to stop at the diagram — Bronze, Silver, Gold, arrows pointing right. What they skip is the production code, the partitioning strategy, the vacuum and Z-order maintenance, and the CU cost model that determines whether the architecture is affordable. This guide fills those gaps. It is written for the data engineer who has already seen the diagram and needs to actually ship the platform.

What the Medallion Layers Do (Precise Definitions)

Bronze layer — raw, append-only, source-fidelity data. Store exactly what arrived, with source system metadata (ingest timestamp, source system, source file, batch ID) attached. Do not clean, deduplicate, or transform in Bronze. Bronze is your immutable source of truth if you need to reprocess.

Silver layer — cleaned and conformed data. Deduplication done. Type coercion done. Business keys resolved. Slowly changing dimension tracking done. Silver is where individual source system data becomes usable for analytics but is not yet business-domain organized.

Gold layer — dimensional models and aggregated tables for consumption. Star schemas for BI, aggregations for dashboards, denormalized flat tables for exports. Gold is what semantic models bind to and what business users see.

The layers correspond to distinct engineering discipline: Bronze prioritizes source fidelity, Silver prioritizes correctness, Gold prioritizes query performance and business usability. If you conflate the layers (e.g., cleaning in Bronze, or joining Silver tables in Gold at query time), you lose the ability to reason about the architecture.

What Fabric Changes About the Pattern

The classic medallion pattern was designed for Databricks or Snowflake — separate compute clusters per layer, ADLS Gen2 storage, Delta or Iceberg tables, and ETL orchestration in ADF or Airflow. Fabric changes three things:

1. OneLake unifies storage. Bronze, Silver, and Gold all live in OneLake as Delta Parquet. No copies between storage layers. Data engineers can shortcut Bronze data into a Silver lakehouse in a different workspace without moving bytes.

2. Fabric Warehouse can be Gold. For structured Gold tables consumed by BI, Fabric Warehouse gives you T-SQL query performance without leaving the platform. Alternately, Gold can be a Lakehouse with a SQL analytics endpoint. Choose based on query workload characteristics.

3. Direct Lake+ collapses Gold-to-semantic-model. In the pre-Fabric world, Gold tables were queried into a Power BI Import model via a refresh pipeline. With Direct Lake+ semantic models, Gold Delta tables in OneLake are queryable directly by Power BI reports with no refresh step. This shortens the pipeline by an entire stage.

Practical result: the Fabric medallion pattern in 2026 is Bronze Lakehouse → Silver Lakehouse → Gold (Warehouse or Lakehouse) → Direct Lake+ semantic model → Power BI report. One platform, one storage layer, one governance surface.

Bronze Layer: Ingest Patterns

Three common Bronze ingest patterns in Fabric:

Pattern 1 — Data Factory pipeline for batch source systems. Fabric Data Factory pulls from Azure SQL, Snowflake, S3, on-prem SQL Server via the on-prem gateway, or REST APIs, and writes to a Bronze Delta table. Use for scheduled batch ingest where 15-minute freshness is acceptable.

Pattern 2 — OneLake shortcut for existing lake data. If source data already lives in ADLS Gen2 or S3, create a Fabric shortcut. No data movement. The Bronze table is a virtual view of the source lake. Use when source data is already Delta or Parquet and refresh schedules are controlled elsewhere.

Pattern 3 — Eventstream for streaming source systems. Fabric Eventstream ingests from Event Hubs, IoT Hub, Kafka, or CDC sources into a KQL database or Delta table in Bronze. Use for real-time analytics where sub-minute freshness matters.

For all patterns, the Bronze table schema follows one rule: preserve source fidelity plus mandatory metadata. A minimal Bronze table schema:

``` BronzeSales/ ingest_timestamp timestamp NOT NULL -- when Fabric ingested source_system string NOT NULL -- 'SAP', 'Salesforce', 'S3-payments' source_batch_id string -- batch/file/message ID source_offset bigint -- for streaming, offset in source raw_data <original schema> -- everything from source, as-is ```

Every Bronze table has these five ingest-metadata columns. Downstream Silver processing depends on them for deduplication and lineage tracing.

Silver Layer: Cleaning + Conforming with PySpark

Silver is where correctness lives. Here's the production PySpark pattern for a typical Silver transform:

```python # notebooks/silver_sales_transform.py from pyspark.sql import functions as F from pyspark.sql.window import Window

bronze_path = "abfss://Silver_Sales@onelake.dfs.fabric.microsoft.com/Tables/BronzeSales" silver_path = "abfss://Silver_Sales@onelake.dfs.fabric.microsoft.com/Tables/Silver_Sales"

df = spark.read.format("delta").load(bronze_path)

# 1. Deduplicate on business key, keeping latest ingest window = Window.partitionBy("raw_data.order_id").orderBy(F.col("ingest_timestamp").desc()) df = df.withColumn("row_num", F.row_number().over(window)).filter(F.col("row_num") == 1).drop("row_num")

# 2. Explode raw_data to flat columns df = df.select( F.col("raw_data.order_id").alias("order_id"), F.col("raw_data.customer_id").alias("customer_id"), F.col("raw_data.order_date").cast("date").alias("order_date"), F.col("raw_data.amount").cast("decimal(18,2)").alias("amount"), F.col("raw_data.currency").alias("currency"), F.col("ingest_timestamp").alias("silver_ingest_timestamp"), F.col("source_system").alias("source_system"), )

# 3. Coerce types + validate ranges df = df.filter(F.col("amount") >= 0) # discard bad rows to a quarantine table if needed

# 4. Add business-key surrogate hash for downstream joins df = df.withColumn("customer_key", F.sha2(F.col("customer_id"), 256))

# 5. Write out with merge (upsert on business key) — this is a Type 1 SCD pattern df.write.format("delta").mode("append").partitionBy("order_date").save(silver_path) ```

Notes on the pattern: - Deduplication with window function is standard for Bronze → Silver transforms. - Type coercion happens explicitly. Never trust source schemas. - Bad row quarantine is optional but recommended for regulated data. Discarded rows go to a "quarantine" Delta table with the failure reason. - Business-key surrogate hashes simplify downstream joins.

Gold Layer: Dimensional Models

Gold tables are where BI semantics live. Two Gold patterns for different workloads:

Pattern A — Star schema in a Fabric Warehouse. Fact and dimension tables in T-SQL. Best for reports that need low-latency query performance and complex joins.

```sql -- Warehouse DDL for Gold CREATE TABLE gold.FactSales ( OrderKey bigint NOT NULL, CustomerKey varbinary(32) NOT NULL, DateKey int NOT NULL, ProductKey int NOT NULL, Amount decimal(18,2) NOT NULL, LineCount int NOT NULL );

CREATE TABLE gold.DimCustomer ( CustomerKey varbinary(32) NOT NULL, CustomerName varchar(200) NOT NULL, Region varchar(50) NOT NULL, Segment varchar(50) NOT NULL ); -- + DimDate, DimProduct ```

Populate with T-SQL MERGE from Silver.

Pattern B — Delta star schema in a Fabric Lakehouse. Same shape as Pattern A but as Delta tables. Best when the Gold layer is consumed by Direct Lake+ semantic models — Delta is required.

Choose Pattern B unless you have a hard requirement for T-SQL query patterns Gold consumers depend on.

Partitioning Strategy per Layer

Partitioning is the most under-thought Delta configuration. The right partitioning strategy per layer:

  • Bronze: partition by ingest date. Simple, matches ingest cadence, retains time-travel capability.
  • Silver: partition by business date (order_date, event_date). Aligns partitions to typical downstream filters.
  • Gold: partition by the highest-cardinality-in-filter column (usually date). For very large facts (100M+ rows), also Z-order on the second-most-filtered column.

Rules of thumb: - Partition count per table should be 10-10,000. Fewer than 10 = negligible benefit. More than 10,000 = metadata overhead dominates. - Partition column cardinality should be 10-1000. Higher than 1000 causes small-file problems. Lower than 10 = no pruning benefit. - Never partition on high-cardinality customer or product IDs. Always partition on time or a low-cardinality category.

Vacuum and Z-Order Maintenance

Delta tables accumulate historical versions. Without maintenance, storage costs balloon and query performance degrades.

Vacuum policy: run every 7 days, retention 30 days for Silver, 90 days for Gold, 7 days for Bronze. Vacuum removes old file versions older than retention.

```python spark.sql(f"VACUUM delta.`{silver_path}` RETAIN 720 HOURS") ```

Z-order policy: run monthly on Gold fact tables. Z-order clusters data on the partition-plus-Z-order columns, dramatically improving query performance on filtered scans.

```python spark.sql(f"OPTIMIZE delta.`{gold_fact_path}` ZORDER BY (CustomerKey, ProductKey)") ```

Both operations consume CU. Schedule them during off-peak hours to avoid impacting user query workloads.

CU Cost Model per Layer

Approximate CU consumption per 1TB of data, per month, with typical Fabric operations:

LayerCU-hours/monthPrimary driver
Bronze ingest40-100Data Factory pipeline execution
Bronze storageIncluded in OneLake$0.023/GB via OneLake
Silver transform80-200PySpark notebook execution
Silver vacuum + optimize15-30Scheduled maintenance
Gold transform40-100T-SQL / Spark writes
Gold vacuum + optimize10-25Scheduled maintenance
Semantic model refresh (if Import)30-80Refresh scheduling
Semantic model queries (Direct Lake+)30-100User query workload
Total per 1TB/month245-635 CU-hours

At F64 (approximately 46,000 CU-hours/month at full utilization), the medallion architecture over 5-10TB of data typically consumes 30-50% of capacity, leaving room for other Fabric workloads.

CI/CD Wrap-Up with fabric-cicd

The Bronze/Silver/Gold notebooks and Data Factory pipelines all deploy through fabric-cicd (the pattern covered in Power BI Deployment Pipelines with PBIP + fabric-cicd). Repository structure:

``` / bronze/ notebooks/BronzeIngest.py pipelines/SalesBronzePipeline.json silver/ notebooks/SilverSalesTransform.py notebooks/SilverCustomerTransform.py gold/ warehouse/star_schema.sql notebooks/GoldFactSalesLoad.py environments/ dev.yaml test.yaml prod.yaml ```

Deploy pipelines by environment. Every environment gets an isolated set of Fabric workspaces so Bronze/Silver/Gold in dev cannot touch prod. Merge-to-main triggers dev deploy; tag-based deploys promote to test and prod.

Related Guides

Ready to design or refactor a medallion architecture in your Fabric estate? Book a 30-minute strategy call and we will size the CU envelope and layer boundaries for your data.

Frequently Asked Questions

What is medallion architecture in Microsoft Fabric?

Medallion is a three-layer data lakehouse pattern: Bronze (raw source-fidelity data), Silver (cleaned and conformed data), Gold (dimensional models and aggregated tables for consumption). In Microsoft Fabric, all three layers live in OneLake as Delta Parquet, unified under one storage layer, one governance surface, and one capacity billing model.

Should Bronze / Silver / Gold be Lakehouses or Warehouses in Fabric?

Bronze is always a Lakehouse (raw Delta ingest). Silver is always a Lakehouse (PySpark transforms are the standard tool). Gold can be either — Fabric Warehouse for workloads that need T-SQL query performance, or Lakehouse for workloads consumed by Direct Lake+ semantic models. Direct Lake+ requires Delta, so Lakehouse Gold is the modern default for BI-facing tables.

What partitioning strategy should I use for each medallion layer?

Bronze: partition by ingest date. Silver: partition by business date (order_date, event_date). Gold: partition by the highest-cardinality-in-filter column (usually date) plus Z-order on the second-most-filtered column for large facts. Aim for 10-10,000 partitions per table with partition cardinality of 10-1000.

How often should I vacuum and optimize Delta tables in Fabric?

Vacuum weekly with retention of 7 days for Bronze, 30 days for Silver, 90 days for Gold. Z-order optimize monthly on Gold fact tables using the top-2 or top-3 most-filtered non-partition columns. Schedule maintenance during off-peak hours to avoid impacting user query workloads. Both operations consume CU.

How much Fabric capacity does a medallion architecture consume?

Approximately 245-635 CU-hours per month per 1TB of data across all layers, depending on refresh frequency and query workload. At F64 (roughly 46,000 CU-hours per month at full utilization), a 5-10TB medallion deployment typically consumes 30-50% of capacity, leaving room for other Fabric workloads.

How does Direct Lake+ change the medallion pattern?

In the classic pattern, Gold tables were refreshed into a Power BI Import semantic model on a schedule. With Direct Lake+ semantic models, Power BI reads Gold Delta tables in OneLake directly with no refresh step. This eliminates one full stage of the pipeline and delivers near-real-time data to BI consumers. Semantic models in Direct Lake+ typically consume 20-40% less CU than equivalent Import models.

How do I deploy medallion architecture across dev / test / prod in Fabric?

Use PBIP + fabric-cicd for semantic models and reports, and version your Data Factory pipelines and PySpark notebooks in the same repository. Each environment gets an isolated set of Fabric workspaces (Bronze/Silver/Gold per environment). Merge-to-main deploys to dev; tag-based deploys promote to test and prod through GitHub Actions or Azure DevOps.

Microsoft FabricMedallion ArchitecturePySparkDelta LakeData Engineering

Industry Solutions

See how we apply these solutions across industries:

Need Help With Power BI?

Our experts can help you implement the solutions discussed in this article.

Ready to Transform Your Data Strategy?

Get a free consultation to discuss how Power BI and Microsoft Fabric can drive insights and growth for your organization.