Microsoft Fabric Cheat Sheet Guide
Quick reference for Microsoft Fabric — from OneLake and Data Factory to Lakehouses, Warehouses, Real-Time Analytics, Power BI integration, and governance.
📋 Quick reference: Microsoft Fabric Cheat Sheet — use this alongside the guide for fast syntax lookup while you read.
Core Components
Microsoft Fabric
An end-to-end SaaS analytics platform from Microsoft. It unifies data engineering, data integration, data warehousing, real-time analytics, and business intelligence under a single product — one tenant, one storage layer (OneLake), one billing unit (Fabric capacity), and one governance model.
Before Fabric, building a modern data platform on Azure meant stitching together separate services: Azure Data Factory for pipelines, Azure Data Lake Storage for files, Synapse Analytics for queries, and Power BI for reporting. Each had its own security model, its own monitoring, and its own way of connecting to the others. Fabric collapses that stack.
Key workloads in Fabric:
| Workload | What it does |
|---|---|
| Data Engineering | Spark notebooks, Lakehouses, Delta tables |
| Data Factory | Pipelines, Dataflows Gen2, data movement |
| Data Warehousing | T-SQL Warehouse, SQL endpoint |
| Real-Time Analytics | Eventstream, KQL Database |
| Power BI | Semantic models, reports, dashboards |
| Data Science | ML experiments, models, notebooks |
OneLake
The single unified storage layer built into every Fabric tenant. All data across all workspaces and all workloads lands here. You do not provision it — it exists automatically when you have a Fabric tenant.
Key properties:
- One lake per organization — all workspaces share the same underlying storage
- Built on Azure Data Lake Storage Gen2 under the hood
- All data stored in Delta Parquet format for structured tables
- Accessible by all Fabric workloads natively — no data copying between services
- Supports shortcuts — virtual links to external storage (ADLS Gen2, AWS S3, GCS) without moving data
Tenant
└── OneLake
├── Workspace A
│ ├── Lakehouse 1 (Tables + Files)
│ └── Warehouse 1
└── Workspace B
└── Lakehouse 2 (Tables + Files)Lakehouse
The primary data storage and processing object in Fabric. A Lakehouse combines the flexibility of a data lake (store any file type) with the structure of a data warehouse (Delta tables with a SQL endpoint).
Two sections:
- Tables — Delta tables. Queryable via SQL endpoint, readable by Spark notebooks and semantic models
- Files — Raw files (CSV, Parquet, JSON, images). Not directly queryable via SQL — process with Spark first
Automatically provides:
- A SQL Analytics Endpoint for T-SQL queries on Tables
- An auto-generated semantic model for Power BI DirectLake connections
Warehouse
A dedicated T-SQL analytics engine on top of OneLake. Designed for SQL-focused teams who need a traditional data warehouse experience — DDL statements, stored procedures, transactions, views — without Spark.
Lakehouse vs Warehouse:
| Lakehouse | Warehouse | |
|---|---|---|
| Primary interface | Spark / SQL endpoint | T-SQL |
| DDL support | Limited (via SQL endpoint) | Full CREATE/ALTER/DROP |
| Stored procedures | No | Yes |
| Transactions | Delta ACID | Full T-SQL transactions |
| Best for | Data engineering + BI | SQL-focused analytics teams |
Data Factory
The data integration workload in Fabric. Orchestrates data movement and transformation — ingesting from external sources into OneLake, triggering notebooks, and scheduling pipeline runs.
Two tools:
- Pipelines — visual workflow orchestration (copy, transform, loop, conditional logic)
- Dataflow Gen2 — no-code Power Query M transformations with OneLake output
Real-Time Analytics
The streaming and time-series analytics workload. Designed for high-velocity event data — IoT telemetry, clickstreams, log data, financial ticks.
Two tools:
- Eventstream — ingest and route real-time event streams from sources like Azure Event Hub, Kafka, and IoT Hub
- KQL Database — store and query time-series data using Kusto Query Language (KQL)
Power BI
The reporting and visualization workload. Natively embedded in Fabric — reports, semantic models, and dashboards are first-class Fabric items that live in workspaces alongside Lakehouses and pipelines.
DirectLake is the connection mode that makes Fabric reporting unique — semantic models read Delta tables in OneLake directly without importing data, delivering import-level query speed with near-real-time freshness.
Workspaces & Storage
Workspace
A container for all Fabric items — Lakehouses, Warehouses, notebooks, pipelines, semantic models, and reports. Every workspace is backed by a folder in OneLake.
Workspace roles:
| Role | Permissions |
|---|---|
| Admin | Full control — manage members, delete workspace |
| Member | Create, edit, publish items — manage permissions |
| Contributor | Create and edit items — cannot manage permissions |
| Viewer | Read-only access to published content |
Best practice: one workspace per domain per environment (e.g. Retail-Sales-Dev, Retail-Sales-Prod). Use deployment pipelines to promote content between environments.
Capacity
The compute and storage billing unit in Fabric. Every workspace must be assigned to a capacity. Capacity is measured in Capacity Units (CUs) and determines how much compute is available for all workloads running in that capacity.
SKUs:
- F SKUs — Fabric capacity (F2 to F2048). Purchased in Azure portal
- P SKUs — Power BI Premium capacity (P1 to P5). Legacy — still supported
- Trial — free 60-day Fabric trial capacity for evaluation
Key concept: all workloads in a capacity share the same CU pool. A heavy Spark notebook job competes with a pipeline run and a semantic model refresh on the same capacity. Monitor with the Fabric Capacity Metrics app.
Shortcuts
Virtual links that make external data appear inside OneLake without physically copying it. A shortcut points to data in ADLS Gen2, AWS S3, Google Cloud Storage, or another OneLake location — and it appears as a folder inside a Lakehouse.
Lakehouse
└── Files
├── shortcut → adls://external-account/raw-data/ (reads live from ADLS)
└── shortcut → s3://partner-bucket/exports/ (reads live from S3)
└── Tables
└── shortcut → OneLake/OtherWorkspace/Lakehouse/ (reads from another workspace)Use cases:
- Query external data without an ETL pipeline
- Share data between workspaces without duplication
- Federate data from partner systems without ingestion
Delta Tables
The standard table format in Fabric. Delta Lake is an open-source storage layer that adds ACID transactions, schema enforcement, and time travel to Parquet files.
Key Delta features:
- ACID transactions — concurrent reads and writes are safe
- Time travel — query data as it existed at any previous version
- Schema enforcement — rejects writes that don't match the table schema
- Schema evolution — can add columns without breaking existing readers
- Optimize & Z-order — compact small files and co-locate related data for faster queries
-- Time travel in SQL endpoint
SELECT * FROM sales_fact
FOR TIMESTAMP AS OF '2024-06-01 00:00:00'
-- Version-based time travel
SELECT * FROM sales_fact
FOR VERSION AS OF 5# Time travel in PySpark notebook
df = spark.read.format("delta") \
.option("versionAsOf", 5) \
.load("Tables/sales_fact")Files Section
The unstructured storage area of a Lakehouse. Stores raw files in any format — CSV, JSON, Parquet, images, PDFs. Files here are not queryable via the SQL endpoint — they must be processed with a Spark notebook before becoming Delta tables.
Common pattern (Medallion):
Files/
├── bronze/ ← raw ingested files land here
│ ├── wms/
│ └── gps/
└── (processed by notebook → written to Tables/ as Delta)Tables Section
The structured Delta table storage area of a Lakehouse. All tables here are:
- Automatically registered in the SQL Analytics Endpoint
- Readable by Spark notebooks as Delta tables
- Accessible by Power BI semantic models via DirectLake
- Discoverable in the OneLake Data Hub
Data Engineering
Notebook
A collaborative, browser-based coding environment in Fabric. Supports Python, PySpark, Scala, SQL, and R in the same notebook. Each cell can use a different language.
Key features:
- Native Spark session — no cluster configuration needed
- Built-in
sparkandmssparkutilsobjects available automatically - Inline Delta table explorer — browse Lakehouse tables without leaving the notebook
- Parameterized notebooks — accept parameters when called from a pipeline
- Version history and Git integration
# Access a Lakehouse table
df = spark.read.format("delta").load("Tables/sales_fact")
# Write a Delta table
df.write.format("delta").mode("overwrite").saveAsTable("gold_sales_summary")
# Run SQL in a Python notebook
df = spark.sql("SELECT region, SUM(amount) FROM sales_fact GROUP BY region")Apache Spark
The distributed compute engine powering data engineering in Fabric. Spark processes data in parallel across a cluster of nodes — enabling transformations on datasets that are too large for single-machine processing.
Fabric Spark concepts:
- Starter pool — a pre-warmed Spark pool that starts in ~15 seconds. Used for most interactive and pipeline notebook runs
- Custom pool — a dedicated Spark cluster with specific node sizes and counts
- High concurrency mode — multiple notebooks share the same Spark session — reduces startup overhead for concurrent pipeline runs
PySpark
The Python API for Apache Spark. Write Python code that executes on the distributed Spark engine. The DataFrame API is the primary interface — it looks similar to pandas but executes across a cluster.
Key PySpark patterns in Fabric:
from pyspark.sql import functions as F
# Read from Lakehouse table
df = spark.read.format("delta").load("Tables/silver_transactions")
# Transform
df_clean = (
df
.filter(F.col("amount") > 0)
.withColumn("month", F.date_trunc("month", F.col("transaction_date")))
.withColumn("margin", F.col("revenue") - F.col("cost"))
)
# Aggregate
df_summary = (
df_clean
.groupBy("region", "month")
.agg(
F.sum("amount").alias("total_sales"),
F.count("transaction_id").alias("order_count"),
F.avg("margin").alias("avg_margin")
)
)
# Write to Gold Lakehouse table
df_summary.write \
.format("delta") \
.mode("overwrite") \
.option("overwriteSchema", "true") \
.saveAsTable("gold_sales_summary")DataFrame
The primary data structure in PySpark. A distributed table with named columns and a schema. Operations on a DataFrame are lazy — they build an execution plan but do not run until an action is called (.show(), .count(), .write()).
# Create from file
df = spark.read.csv("Files/bronze/sales.csv", header=True, inferSchema=True)
# Create from Delta table
df = spark.read.format("delta").load("Tables/silver_sales")
# Schema inspection
df.printSchema()
df.dtypes
# Basic operations
df.show(5)
df.count()
df.columns
df.select("region", "amount").distinct()
df.filter(df.amount > 1000)
df.orderBy("amount", ascending=False)Save as Table
Write a DataFrame as a Delta table in the Lakehouse Tables section. Two methods — saveAsTable registers in the metastore; save writes to a path only.
# saveAsTable — registers table in metastore (preferred)
df.write \
.format("delta") \
.mode("overwrite") \
.saveAsTable("gold_sales_summary")
# save — writes to path, not registered automatically
df.write \
.format("delta") \
.mode("append") \
.save("Tables/gold_sales_summary")
# With partitioning
df.write \
.format("delta") \
.mode("overwrite") \
.partitionBy("region", "year") \
.saveAsTable("gold_sales_partitioned")Semantic Link
A Python library (sempy) that lets Fabric notebooks interact directly with Power BI semantic models — read data, evaluate DAX measures, and push data back to semantic models from a notebook.
import sempy.fabric as fabric
# List semantic models in the workspace
fabric.list_datasets()
# Read a table from a semantic model
df = fabric.read_table("Sales Semantic Model", "FactSales")
# Evaluate a DAX measure
result = fabric.evaluate_dax(
"Sales Semantic Model",
"""
EVALUATE
SUMMARIZECOLUMNS(
DimDate[Year],
"Total Sales", [Total Sales]
)
"""
)Data Factory & Pipelines
Pipeline
A visual workflow that orchestrates data movement and transformation. A pipeline is a sequence of activities that execute in a defined order, with conditional branching, loops, and error handling.
Common activity types:
| Activity | Purpose |
|---|---|
| Copy Data | Move data from source to destination |
| Notebook | Run a Fabric notebook |
| Dataflow Gen2 | Run a dataflow transformation |
| Script | Execute a SQL script |
| Web | Call a REST API |
| ForEach | Loop over a list of items |
| If Condition | Branch based on a condition |
| Set Variable | Store a value for use later in the pipeline |
| Wait | Pause for a specified duration |
Copy Activity
The workhorse of data ingestion — moves data from a source connector to a destination. Supports 90+ connectors including SQL Server, SharePoint, REST APIs, SFTP, S3, ADLS, and more.
Key settings:
- Source — connection + dataset (table, query, or file path)
- Sink — destination connection + write behaviour (overwrite, append, merge)
- Mapping — column-level field mapping between source and destination
- Performance — degree of copy parallelism, staging settings
Common pattern — land raw files to Lakehouse Files:
Source: SharePoint Online (Excel file)
↓ Copy Activity
Sink: Lakehouse Files section → /bronze/sales/YYYY-MM-DD/Dataflow Gen2
A no-code/low-code transformation tool using the Power Query M engine. Drag-and-drop transformations that output to a Lakehouse table, Warehouse table, or other destination.
When to use Dataflow Gen2 vs Notebook:
| Dataflow Gen2 | Notebook | |
|---|---|---|
| Audience | Analysts, low-code users | Engineers, data scientists |
| Language | Power Query M (visual) | Python, PySpark, SQL, Scala |
| Best for | Simple transformations, reshaping | Complex logic, large data, ML |
| Scale | Limited Spark compute | Full Spark cluster |
Schedule Pipeline
Trigger a pipeline on a time-based cadence — without writing any code.
Steps:
- Open the pipeline → Schedule tab
- Toggle Scheduled on
- Set recurrence: Daily, Weekly, Monthly, or Custom (cron)
- Set start time and timezone
- Save
Trigger types:
- Scheduled — runs on a time cadence
- Manual — triggered by a user clicking Run
- Event-based — triggers when a file lands in OneLake (via Storage Event trigger)
- Pipeline — triggered by another pipeline completing
Parameters
Make pipelines reusable by parameterizing values that change between runs — file paths, dates, DC IDs, environment names.
// Pipeline parameters definition
{
"run_date": { "type": "string", "defaultValue": "" },
"dc_id": { "type": "string", "defaultValue": "ALL" },
"env": { "type": "string", "defaultValue": "dev" }
}# Access pipeline parameters inside a Fabric notebook
run_date = mssparkutils.runtime.context.get("run_date")
dc_id = mssparkutils.runtime.context.get("dc_id")Monitor Hub
The central observability dashboard for all Fabric activity — pipeline runs, notebook executions, Spark jobs, dataflow runs, and more.
Access: Left nav → Monitor
Key views:
- Pipeline runs — status, duration, start/end time, triggered by
- Notebook runs — execution history, Spark session details
- Background jobs — scheduled refresh, dataflow runs
Useful for: debugging failed runs, tracking data latency, capacity utilization monitoring, and auditing who ran what and when.
SQL & Warehousing
SQL Endpoint
A read-only T-SQL interface automatically provisioned for every Lakehouse. Exposes all Delta tables in the Lakehouse's Tables section as queryable SQL objects — no setup required.
Key properties:
- Read-only — cannot INSERT, UPDATE, or DELETE via the SQL endpoint
- Tables appear automatically as soon as they are written to the Lakehouse
- Supports views and stored procedures (via Warehouse, not SQL endpoint)
- Connection string available for external tools (SSMS, Azure Data Studio, Power BI)
-- Query via SQL endpoint
SELECT
region,
SUM(amount) AS total_sales,
COUNT(*) AS order_count
FROM gold_sales_summary
GROUP BY region
ORDER BY total_sales DESC;T-SQL
The query language for Fabric Warehouse and the SQL Analytics Endpoint. Standard T-SQL syntax — SELECT, JOIN, WHERE, GROUP BY, window functions, CTEs.
-- Standard query
SELECT
c.customer_name,
d.year,
d.month_name,
SUM(f.amount) AS monthly_sales
FROM fact_sales f
JOIN dim_customer c ON f.customer_key = c.customer_key
JOIN dim_date d ON f.date_key = d.date_key
GROUP BY c.customer_name, d.year, d.month_name
ORDER BY d.year, d.month_name;
-- Window function
SELECT
region,
sale_date,
daily_sales,
SUM(daily_sales) OVER (
PARTITION BY region
ORDER BY sale_date
ROWS UNBOUNDED PRECEDING
) AS running_total
FROM daily_sales_summary;Stored Procedure
Reusable T-SQL logic stored in a Fabric Warehouse. Executes a sequence of SQL statements as a unit. Only available in Warehouse — not in the SQL endpoint.
CREATE PROCEDURE usp_refresh_gold_summary
@run_date DATE = NULL
AS
BEGIN
SET @run_date = COALESCE(@run_date, CAST(GETDATE() AS DATE));
DELETE FROM gold_daily_summary
WHERE summary_date = @run_date;
INSERT INTO gold_daily_summary (summary_date, region, total_sales, order_count)
SELECT
@run_date,
region,
SUM(amount),
COUNT(*)
FROM silver_transactions
WHERE CAST(transaction_date AS DATE) = @run_date
GROUP BY region;
END;
-- Execute
EXEC usp_refresh_gold_summary @run_date = '2024-06-15';View
A saved SELECT query that behaves like a virtual table. Available in both Warehouse and via SQL endpoint.
-- Create a view in Fabric Warehouse
CREATE VIEW vw_active_customer_sales AS
SELECT
c.customer_key,
c.customer_name,
c.region,
SUM(f.amount) AS lifetime_sales,
COUNT(*) AS total_orders
FROM fact_sales f
JOIN dim_customer c ON f.customer_key = c.customer_key
WHERE c.is_active = 1
GROUP BY c.customer_key, c.customer_name, c.region;CTAS
Create Table As Select — create a new table from a query result. Useful for materializing aggregations and Gold layer tables in a Warehouse.
-- Create Gold summary table from Silver data
CREATE TABLE gold_region_summary
AS
SELECT
region,
YEAR(sale_date) AS sale_year,
MONTH(sale_date) AS sale_month,
SUM(amount) AS total_sales,
COUNT(*) AS order_count,
AVG(amount) AS avg_order_value
FROM silver_transactions
WHERE amount > 0
GROUP BY region, YEAR(sale_date), MONTH(sale_date);Star Schema
The recommended data model pattern for Fabric Warehouse and Lakehouse Gold layer. One central fact table surrounded by dimension tables.
-- Fact table — one row per transaction
CREATE TABLE fact_sales (
sale_key BIGINT NOT NULL,
date_key INT NOT NULL, -- FK to dim_date
customer_key INT NOT NULL, -- FK to dim_customer
product_key INT NOT NULL, -- FK to dim_product
store_key INT NOT NULL, -- FK to dim_store
quantity INT,
unit_price DECIMAL(10,2),
amount DECIMAL(12,2),
cost DECIMAL(12,2)
);
-- Dimension table — one row per customer
CREATE TABLE dim_customer (
customer_key INT NOT NULL PRIMARY KEY,
customer_id VARCHAR(20) NOT NULL,
customer_name VARCHAR(200),
region VARCHAR(50),
country VARCHAR(50),
is_active BIT DEFAULT 1
);Real-Time Analytics
Eventstream
A no-code pipeline for ingesting, transforming, and routing real-time event streams. Connects sources (Azure Event Hub, Kafka, IoT Hub, sample data) to destinations (KQL Database, Lakehouse, another Eventstream).
Key concepts:
- Source — where events come from (Event Hub, Kafka, IoT Hub, custom app)
- Transformation — filter, aggregate, or reshape events in flight
- Destination — where processed events land (KQL Database, Lakehouse table, Warehouse)
Common pattern:
IoT sensors → Azure IoT Hub → Eventstream → KQL Database (real-time)
→ Lakehouse (batch history)KQL Database
A time-series optimized database in Fabric. Built on the same engine as Azure Data Explorer. Designed for high-velocity append-only data — telemetry, logs, metrics, events.
Key properties:
- Columnar storage optimized for time-range queries
- Auto-ingestion from Eventstream
- Data expires automatically based on retention policy
- Accessible from Real-Time Dashboards and Power BI
// Basic KQL query
SensorReadings
| where ingestion_time() > ago(1h)
| where device_id == "DC-001"
| summarize avg_temp = avg(temperature) by bin(timestamp, 5m)
| order by timestamp descKusto Query Language (KQL)
The query language for KQL Databases. Pipe-based syntax — each operator passes its result to the next.
// Filter and aggregate
DeliveryEvents
| where event_time > ago(24h)
| where event_type == "delivered"
| summarize
total_deliveries = count(),
on_time = countif(is_on_time == true),
avg_delay_minutes = avg(delay_minutes)
by dc_id, bin(event_time, 1h)
| extend on_time_rate = round(todouble(on_time) / total_deliveries * 100, 1)
| order by event_time desc
// Join two tables
DeliveryEvents
| join kind=leftouter DriverInfo on $left.driver_id == $right.driver_id
| project event_time, driver_name, dc_id, is_on_timeCommon KQL operators:
| Operator | Purpose |
|---|---|
where |
Filter rows |
summarize |
Aggregate |
extend |
Add a calculated column |
project |
Select columns |
order by |
Sort results |
join |
Join two tables |
bin() |
Round timestamps to buckets |
ago() |
Relative time expression |
countif() |
Count rows matching a condition |
Real-Time Dashboard
A live dashboard that runs KQL queries on a schedule — updating automatically without manual refresh. Tiles can show line charts, bar charts, maps, stat cards, and tables.
Key features:
- Auto-refresh interval (as low as 30 seconds)
- Parameter controls for time range and dimension filters
- Shareable via Fabric workspace — no Power BI license required for viewers
- Embeddable in external portals
Streaming Data
General patterns for working with real-time data in Fabric.
// Query most recent N events
SensorReadings
| top 100 by ingestion_time() desc
// Detect anomalies in the last hour
SensorReadings
| where ingestion_time() > ago(1h)
| summarize avg_val = avg(value), std_val = stdev(value) by sensor_id
| extend z_score = (avg_val - 50) / std_val
| where abs(z_score) > 2
// Time-series aggregation
ClickEvents
| where event_time > ago(7d)
| summarize clicks = count() by bin(event_time, 1h), page_id
| render timechartPower BI Integration
Semantic Model
The DAX layer that sits between OneLake data and Power BI reports. Defines measures, relationships, hierarchies, and security rules. In Fabric, semantic models are first-class workspace items — not embedded inside a .pbix file.
Two types in Fabric:
- Default semantic model — auto-generated by every Lakehouse and Warehouse. Always in sync with the tables. Cannot be modified directly
- Custom semantic model — a semantic model you build manually, pointing at Lakehouse or Warehouse tables via DirectLake
Direct Lake
The connection mode that makes Fabric reporting distinct from traditional Power BI.
How it works: instead of copying data into the VertiPaq in-memory engine (Import) or querying the source live on every visual interaction (DirectQuery), DirectLake reads Delta table column segments from OneLake on demand. The engine loads what it needs into memory as queries arrive — delivering near-import performance with near-real-time data freshness.
DirectLake vs Import vs DirectQuery:
| Mode | Data freshness | Query speed | Dataset size limit | Requires Fabric? |
|---|---|---|---|---|
| Import | Refresh cadence | Fastest | ~10GB practical | No |
| DirectQuery | Real-time | Slowest | Unlimited | No |
| Direct Lake | Near real-time | Near import | Unlimited | Yes |
Fallback behavior: if a DAX query cannot be served from memory, DirectLake automatically falls back to DirectQuery against the SQL endpoint. Monitor fallback rate in the Fabric Capacity Metrics app.
# After writing Gold tables to Lakehouse, semantic model picks them up automatically
# No refresh needed for DirectLake — data is live from OneLake
df_gold.write.format("delta").mode("overwrite").saveAsTable("gold_sales_summary")Import Mode
Data is copied from the source into the VertiPaq in-memory engine at refresh time. Fast queries. Data is only as fresh as the last refresh. Practical size limit of around 10GB per dataset on Pro; larger on Premium/Fabric.
Use Import when: data does not live in Fabric, volume is manageable, and hourly or daily freshness is acceptable.
DAX
The measure language for Power BI semantic models in Fabric. DAX measures evaluate dynamically based on filter context — the slicers, visual filters, and page filters active when a query runs.
-- Basic measure
Total Sales = SUM(fact_sales[amount])
-- CALCULATE modifies filter context
Sales USA =
CALCULATE([Total Sales], dim_customer[country] = "USA")
-- Year-over-year comparison
Sales YoY % =
VAR Current = [Total Sales]
VAR Prior = CALCULATE([Total Sales], SAMEPERIODLASTYEAR(dim_date[date]))
RETURN DIVIDE(Current - Prior, Prior, 0)
-- DirectLake-compatible measure (avoid SUMMARIZE on large tables)
Region Count =
COUNTROWS(SUMMARIZE(fact_sales, dim_customer[region]))Report
A Power BI report published to a Fabric workspace. A collection of pages with interactive visuals — charts, tables, matrices, slicers, cards. Reports connect to a semantic model.
In Fabric: reports are created in Power BI Desktop and published, or created directly in the Service using the new web authoring experience.
Dashboard
A single-page canvas of pinned tiles from one or more reports. Used for high-level monitoring — pin the most important KPI visuals from multiple reports into one view.
Reports vs Dashboards:
| Report | Dashboard | |
|---|---|---|
| Pages | Multiple | Single canvas |
| Interactivity | Full cross-filtering | Limited (tiles are static) |
| Data sources | One semantic model | Multiple reports/models |
| Best for | Deep analysis | Executive summary KPIs |
Security & Governance
Microsoft Purview
Microsoft's unified data governance platform — integrated with Fabric. Provides data cataloging, lineage, classification, and compliance management across all Fabric items and OneLake data.
Key Purview capabilities in Fabric:
- Data catalog — discover and document all tables, pipelines, and semantic models across the tenant
- Data lineage — trace where data came from, what transformed it, and where it flows to
- Sensitivity labels — classify data (Confidential, Highly Confidential, Public) and enforce protection policies
- Information protection — encrypt labeled data, restrict export, apply watermarks
Row-Level Security (RLS)
Restrict which rows of data each user can see. Defined in the semantic model using DAX filter expressions — enforced by the Power BI engine at query time.
-- In the semantic model role filter on dim_store
[store_manager_email] = USERPRINCIPALNAME()
-- More complex — managers see their region
[region] = LOOKUPVALUE(
dim_manager[region],
dim_manager[email], USERPRINCIPALNAME()
)Steps:
- In Power BI Desktop → Modeling → Manage Roles
- Create a role and add a DAX filter on the relevant dimension table
- Publish to Fabric workspace
- In the workspace → Semantic model → Security → assign users/groups to roles
RLS does not apply to: Warehouse direct SQL connections via SSMS or Azure Data Studio — those respect SQL-level permissions instead.
Sensitivity Labels
Classify Fabric items and OneLake data according to your organization's information protection policy. Labels flow downstream — a Lakehouse table labeled Confidential propagates that label to reports built on it.
Label tiers (example):
- Public — non-sensitive, shareable externally
- General — internal use
- Confidential — business-sensitive data
- Highly Confidential — regulated data (PII, PHI, financial)
Set labels: open any Fabric item → ... menu → Apply sensitivity label
Data Lineage
Visual tracing of data flow through a Fabric workspace — from source through pipelines, Lakehouses, semantic models, to reports.
Access: Workspace → Lineage view (top-right toggle)
Shows:
- Which pipelines feed which Lakehouses
- Which Lakehouses feed which semantic models
- Which semantic models feed which reports
- Impact analysis — what breaks if you change a table
Workspace Roles
Control who can do what inside a Fabric workspace.
Admin → full control, manage members, delete workspace
Member → create/edit/publish all items, manage data source permissions
Contributor → create/edit items, cannot publish apps or manage permissions
Viewer → read-only, can view reports and dashboards through the workspaceBest practice: end users should access content through a published App, not direct workspace access. Give end users the app consumer role — not workspace Viewer — so they only see published content, not works in progress.
Best Practices
Use Medallion Architecture
Organize Lakehouse data into three layers — Bronze, Silver, Gold. Each layer has a clear responsibility and clean separation of concerns.
Bronze → raw data as ingested, no transformation, append-only audit trail
Silver → cleaned, conformed, deduplicated, correctly typed
Gold → aggregated, business-ready, optimized for reporting and semantic models# Bronze — land raw data as-is
df_raw.write.format("delta").mode("append") \
.save("Files/bronze/wms/2024-06-15/")
# Silver — clean and conform
df_silver = df_raw \
.dropDuplicates(["transaction_id"]) \
.withColumn("sale_date", F.to_date("transaction_timestamp")) \
.filter(F.col("amount") > 0)
df_silver.write.format("delta").mode("overwrite").saveAsTable("silver_transactions")
# Gold — aggregate for reporting
df_gold = df_silver.groupBy("region", "sale_date") \
.agg(F.sum("amount").alias("daily_sales"))
df_gold.write.format("delta").mode("overwrite").saveAsTable("gold_daily_sales")Optimize Delta Tables
Keep Delta tables performant as they grow by running OPTIMIZE and VACUUM regularly.
# OPTIMIZE — compact small files into larger ones (improves read performance)
spark.sql("OPTIMIZE gold_daily_sales")
# Z-ORDER — co-locate related data for faster filtered queries
spark.sql("OPTIMIZE silver_transactions ZORDER BY (region, sale_date)")
# VACUUM — remove old Delta versions to reclaim storage
# Default retention = 7 days. Do not set below 7 days for active tables
spark.sql("VACUUM silver_transactions RETAIN 168 HOURS")
# Check table history
spark.sql("DESCRIBE HISTORY silver_transactions").show(10)Separate Storage & Compute
OneLake separates storage from compute — take advantage of it. Do not size your capacity for peak load if average load is much lower. Use job clusters (via pipeline-triggered notebooks) that spin up for a job and terminate when done.
Pattern:
Capacity (F8 or F16) — sized for average interactive workload
Pipeline-triggered notebook — runs on a Spark session that terminates on completion
Result: you pay for compute only while the job runsPrefer Direct Lake
When your data already lives in a Fabric Lakehouse or Warehouse, use DirectLake for semantic models instead of Import. It removes the refresh window, eliminates the dataset size ceiling, and keeps reports current with the latest pipeline run.
When to use DirectLake: data in Fabric Lakehouse/Warehouse + freshness matters
When to use Import: data outside Fabric + small volume + simple refresh cadence
When to use DirectQuery: absolute real-time requirement + source can handle query loadImplement Naming Standards
Consistent naming across workspaces, Lakehouses, tables, pipelines, and notebooks prevents the "14 workspaces, nobody knows what owns what" problem.
Workspaces: [Team]-[Domain]-[Env]
Retail-Sales-Dev, Retail-Sales-Prod
Lakehouses: [Domain]_[Layer]_LH
Sales_Bronze_LH, Sales_Gold_LH
Tables: [layer]_[entity]
bronze_raw_transactions
silver_transactions
gold_daily_sales
Pipelines: [Domain]_[Action]_Pipeline
Sales_Ingest_Pipeline
Sales_Transform_Pipeline
Notebooks: [Domain]_[Layer]_[Action]_NB
Sales_Silver_Clean_NB
Sales_Gold_Aggregate_NBPart of the FTTG Learn Cheat Sheet series — fttgsolutions.com