DirectLake on OneLake is one of those “this is what we’ve been waiting for” features in Microsoft Fabric—until you try to deploy it cleanly across Dev → Test → Prod and realize you’ve re-entered the world of post-deployment manual fixes.
In this how-to, I’m going to do three things:
- Contrast DirectLake on SQL endpoints (the “classic” flavor) with DirectLake on OneLake (the newer flavor), and explain why OneLake is worth the trouble.
- Walk through the normal deployment pipeline approach that works well for DirectLake on SQL.
- Show a two-step, semi-automated approach for DirectLake on OneLake using:
sempy_labs.directlake.update_direct_lake_model_connection(), and- a Fabric Variable Library + a “run-after-deployment” notebook.
Along the way, I’ll call out the current challenges (because yes, they’re real right now), and why this pattern matters for serious Microsoft Fabric Power BI CI/CD work.
DirectLake has two flavors—and the deployment story changes depending on which you choose
Microsoft now describes two options for Direct Lake tables in semantic models:
- Direct Lake on OneLake (preview): can use one or more Fabric sources backed by Delta tables; does not fall back to DirectQuery via the SQL analytics endpoint; can coexist with Import tables in the same semantic model.
- Direct Lake on SQL endpoints: uses a single Fabric source; relies on the SQL analytics endpoint for discovery/permission checks and can fall back to DirectQuery (for example, views or certain security patterns).
The Power BI team summarized the practical differences clearly:
- OneLake flavor is multi-source (mix Lakehouse/Warehouse tables in one model).
- OneLake flavor never uses DirectQuery fallback.
- SQL flavor is single-source and can use the SQL endpoint + fallback behavior.
That’s the upside—and it’s a big one. But it also explains why “just use deployment rules” stops working when you move to OneLake.
The current challenge: deployment rules are not supported for DirectLake on OneLake
If you’ve tried to use Deployment Pipelines with a DirectLake on OneLake semantic model, you’ve probably seen it: deployment rules are greyed out, which means you can’t automatically rebind the semantic model to the “next environment” data source as part of promotion.
This isn’t just a UI quirk. It’s a known gap that currently blocks the clean Dev/Test/Prod re-binding story that teams depend on for ALM.
So the real-world situation today looks like this:
- DirectLake on OneLake is the better architecture for many models (multi-source, no fallback, more “lake-native”).
- But deployment pipelines can’t yet do the “environment binding” step for you.
That forces you to choose between:
- reverting to the SQL flavor (purely to make CI/CD easier), or
- keeping OneLake and adopting a post-deployment binding step.
This post is about that second option.
Why DirectLake on OneLake is still worth it (over DirectLake on SQL)
Even with the current deployment friction, the OneLake flavor brings meaningful advantages:
Multi-source semantic models
You can build a single semantic model across multiple Lakehouses/Warehouses, which is simply not the story with the SQL flavor.
No dependency on SQL endpoint behavior for fallback
DirectLake on OneLake does not fall back to DirectQuery via the SQL analytics endpoint. That can simplify performance expectations and reduce “why is this table suddenly DirectQuery?” surprises.
Composite flexibility
A semantic model can include Direct Lake on OneLake tables and Import tables. That matters when you’re integrating “lake-scale facts” with smaller reference data coming from external systems.
More lake-native governance direction
OneLake flavor aligns with the direction of OneLake-centric governance and security patterns (and, importantly, avoids adding a “SQL layer dependency” to every model design decision).
One important reality check: Direct Lake on OneLake is still listed as public preview, and the tenant setting still reflects that. Treat this as a feature you validate intentionally before betting production SLAs on it.
The “normal” approach: DirectLake on SQL + deployment pipelines (one-step)
When you build DirectLake semantic models in the SQL flavor, the deployment pipeline experience is closer to what BI teams are used to:
- You promote from Dev → Test → Prod
- You use deployment rules to change the binding so that the semantic model in Test points to the Test Lakehouse (instead of still pointing to Dev).
DataZoe also calls out the core difference: with DirectLake on SQL, the connector accepts binding to different sources and the deployment rules workflow behaves as expected.
So the SQL flavor is the “single-step” story:
Deploy via pipeline → deployment rules rebind data source → done.
DirectLake on OneLake is not that story (yet).
The two-step approach for DirectLake on OneLake: deploy, then rebind with Sempy Labs
Here’s the pattern that’s working well for teams who want OneLake benefits and repeatable deployments:
Step 1: Use your standard promotion mechanism (Deployment Pipelines / Git / release process) to deploy the semantic model artifact.
Step 2: Run a notebook after deployment to programmatically rebind the semantic model’s Direct Lake connection(s) to the correct environment sources.
The key enablers:
sempy_labs.directlake.update_direct_lake_model_connection()can switch a model’s connection and explicitly supports using the OneLake expression (use_sql_endpoint=False).- A Fabric Variable Library gives you environment-specific values without hardcoding them into the notebook. Variable libraries are explicitly designed to store different values per release stage, and consumers resolve values based on their own context.
This is where the “semi-automated” part becomes real: the notebook stays the same, the environment config changes.
How to implement it
Prerequisites that will save you hours
Before you build automation that edits semantic models:
- XMLA read/write must be enabled when doing write operations through TOM-based tooling. This is called out directly in SemPy’s TOMWrapper documentation, and Semantic Link Labs mirrors this requirement.
- If you plan to run notebooks non-interactively (pipelines/job scheduler), understand service principal behavior and limitations. Fabric documents the supported patterns for service-principal-triggered notebook runs.
Step 1: Create a Variable Library that holds your environment bindings
Create a variable library (for example, vl_directlake_bindings) with values that differ across Dev/Test/Prod.
You’re aiming to store things like:
- Semantic model name (or ID)
- Target source type:
LakehouseorWarehouse - Target source name
- Target source workspace (name or GUID)
- Whether to use SQL endpoint: False for DirectLake on OneLake
Why a variable library (instead of notebook parameters hardcoded per workspace)?
Because variable libraries are meant to be the central configuration surface for ALM. They support per-stage values, and—crucially—the consumer resolves the value based on where it runs, not based on when it was deployed.
Security note (don’t skip this): variable libraries are items with their own permissions, and Microsoft explicitly warns about the risk of letting untrusted users edit shared configuration values. Lock down write permissions intentionally.
Step 2: Create a “run-after-deployment” notebook
Create a Fabric notebook named something like:
PostDeploy_Rebind_DirectLake_Onelake
This notebook should do one job: rebind the semantic model to the correct OneLake sources using environment-resolved variables.
Below is a practical implementation pattern.
Notebook example (core logic)
# If needed (often it's already available in Fabric notebooks)
%pip install -U semantic-link-labs
import sempy_labs as labs
from sempy_labs.variable_library import get_variable_values
from sempy_labs.directlake import update_direct_lake_model_connection
# --- Configuration (stable names, values come from the variable library) ---
VARIABLE_LIBRARY_NAME = "vl_directlake_bindings"
# Pull values from the variable library (active value set in THIS workspace)
vals = get_variable_values(
variable_names=[
"SemanticModelName",
"SemanticModelWorkspace",
"DirectLakeSourceType",
"DirectLakeSourceName",
"DirectLakeSourceWorkspace",
"UseSqlEndpoint",
# Optional: "TablesToUpdate" (comma-separated list) for multi-source patterns
],
variable_library=VARIABLE_LIBRARY_NAME
)
dataset = vals["SemanticModelName"]
workspace = vals["SemanticModelWorkspace"]
source_type = vals["DirectLakeSourceType"] # "Lakehouse" or "Warehouse"
source_name = vals["DirectLakeSourceName"]
source_workspace = vals["DirectLakeSourceWorkspace"]
use_sql_endpoint = bool(vals["UseSqlEndpoint"]) # For OneLake flavor: False
# Optional: only update specific tables (helpful for multi-source DirectLake on OneLake)
tables = None
# if "TablesToUpdate" in vals and vals["TablesToUpdate"]:
# tables = [t.strip() for t in vals["TablesToUpdate"].split(",")]
# --- Rebind the model ---
update_direct_lake_model_connection(
dataset=dataset,
workspace=workspace,
source=source_name,
source_type=source_type,
source_workspace=source_workspace,
use_sql_endpoint=use_sql_endpoint,
tables=tables
)
print(f"Rebound '{dataset}' in '{workspace}' to {source_type}='{source_name}' (use_sql_endpoint={use_sql_endpoint}).")
A few things to call out:
update_direct_lake_model_connection()is explicitly designed to remap the Direct Lake connection, and the docs clearly state that settinguse_sql_endpoint=Falseuses the Direct Lake over OneLake expression.- Variable library values can be retrieved via Semantic Link Labs’ variable library helpers (
get_variable_value/get_variable_values).
This notebook is intentionally small, boring, and repeatable. That’s the point.
Step 3: Wire it into your release process (so it runs after promotion)
Deployment pipelines don’t currently execute notebooks as part of the promotion itself, so the pattern becomes:
- Promote content (Dev → Test or Test → Prod)
- Then trigger the notebook in the target workspace using your orchestration tool of choice
Common options teams use:
- A Fabric pipeline that runs the notebook as an activity
- A scheduled job / API-triggered notebook run (often service-principal authenticated)
Fabric explicitly documents service-principal-triggered notebook runs (including Fabric Pipelines and the Job Scheduler API), which is exactly what you want when you move from “semi-automated” to “fully automated.”
Why this pattern matters (and why it’s more than a workaround)
This isn’t just about avoiding a manual rebind step.
This approach gives you:
- Environment portability: the semantic model artifact can be deployed consistently, while bindings are resolved at runtime via configuration.
- Repeatability: the “same release” promoted twice behaves the same way—because the binding step is code, not tribal knowledge.
- Safer operations: the variable library becomes the single place to update environment-specific references, instead of editing models by hand.
- A path forward: when deployment rules eventually support DirectLake on OneLake, you can reevaluate. Until then, you have a working ALM story that supports the OneLake architecture.
And in the meantime, you still get the real architectural benefits of DirectLake on OneLake that are driving people there in the first place: multi-source models, no fallback dependency, and a more lake-native semantic layer.
Sidebar: SemPy vs. Sempy Labs (Semantic Link vs. Semantic Link Labs)
SemPy (Semantic Link) is Microsoft’s Python library surface for working with Fabric semantic models and related Fabric artifacts from notebooks. It’s designed to connect the “data science notebook world” to semantic models, metadata, and Fabric APIs.
Semantic Link Labs (Sempy Labs) is an open-source companion library that extends Semantic Link with additional utilities for automation and management—especially the kind of work you’d otherwise do manually in the portal or in external tooling. Microsoft positions it as a way to simplify technical processes and automate machine-suited tasks.
In this deployment pattern:
- SemPy is the foundation (connectivity, TOM concepts, Fabric context).
- Sempy Labs provides the “deployment glue”: DirectLake connection helpers and variable library access that make automation practical.
Closing: DirectLake on OneLake is ready for serious design—CI/CD just needs one more piece
To recap what we covered:
- DirectLake on OneLake brings major benefits (multi-source, no fallback, composite flexibility), but it’s still preview and deployment rules aren’t supported today.
- DirectLake on SQL has a clean one-step CI/CD story with deployment rules.
- For OneLake, a two-step pattern works well right now:
- deploy/promote the artifact,
- then run a “post-deploy” notebook that rebinds the model using Sempy Labs + a variable library.
If you’re building a Fabric ALM strategy in 2026, this is one of those patterns worth standardizing early—because it turns a brittle manual step into a controlled, reviewable, repeatable part of the release process.