arrow_back All posts

My Semantic Model Moved to Prod and Kept Reading Dev: Rebinding Direct Lake with a Fabric Deployment Plan

A Korean folk painting under a swirling Van Gogh style sky, where porters carry a palanquin across a bridge from a pavilion marked DEV to one marked PROD, a red thread still trails back to the DEV pavilion, and a woman in hanbok on the shore draws a red thread toward PROD with a long pole, beside a Korean verse that reads: the bridge is crossed, yet the thread is still tied to the old lake

In this writing, I want to share how a deployment pipeline moved my SpaceParts semantic model from Dev to Prod and left it reading the Dev lakehouse, and how a Fabric deployment plan, with one notebook as a post-deployment action, finally pointed it at Prod.

My plan was simple. Deployment plans are a new item in Fabric, in preview, that add an order and actions to a deployment, and my model needed exactly one action: something to point it at the Prod lakehouse after every deployment. I expected one plan, one action and one deployment. It took a notebook I first ran by hand, an error that told me exactly what was missing, a deployment that failed and still deployed the model, an arrow drawn the wrong way round, and a refresh I had to take out of the notebook. Each of those taught me something about how a plan runs, so I want to walk through them in the order they happened.

1. Two IDs in One Line of expressions.tmdl

The sample is SpaceParts. I have two workspaces, SpaceParts for Dev and SpaceParts Production for Prod, each connected to its own Git repository, and a deployment pipeline called SpaceParts_deployment with two stages, SpaceParts Dev and SpaceParts Prod. Before the first deployment, all four items in Dev were marked Only in source: the SpaceParts lakehouse, the Load SpaceParts data notebook that fills it, the semantic model spaceparts_directlake_import_semanticmodel, and the report spaceparts_report.

The SpaceParts_deployment pipeline with the SpaceParts Dev stage linked to the SpaceParts workspace and the SpaceParts Prod stage linked to SpaceParts Production, both workspace names highlighted, and below them a semantic model, a report, a lakehouse and a notebook, each marked Only in source in the highlighted Compared to source column

The semantic model is composite. Four tables, orders, invoices, budget and forecast, are Direct Lake on OneLake. Ten tables are Import, and the rest are calculated tables such as Date, Reporting Currency and the Time Intelligence calculation group. The Direct Lake tables and the Import tables both read from the same lakehouse, but they find it in two different ways, and both ways had to be repointed later.

The Direct Lake tables find it by ID. The Dev lakehouse opens at an address that carries two IDs, the workspace 1616f463-89fb-42c3-9cda-281809c16629 and the lakehouse a9779aaf-d8a9-4b22-898e-108ae23fa0d6.

The SpaceParts lakehouse open in the Dev workspace, with the workspace ID 1616f463-89fb-42c3-9cda-281809c16629 and the lakehouse ID a9779aaf-d8a9-4b22-898e-108ae23fa0d6 highlighted in the address bar, and the Explorer listing fourteen tables under the SpaceParts schema

The same two IDs sit on line 3 of expressions.tmdl, inside the AzureStorage.DataLake URL of the shared expression DirectLake - SpaceParts. All four Direct Lake partitions name that expression as their source.

expressions.tmdl open in VS Code from the spaceparts_project repository, with line 3 holding the AzureStorage.DataLake URL of the DirectLake - SpaceParts expression and the two IDs 1616f463-89fb-42c3-9cda-281809c16629 and a9779aaf-d8a9-4b22-898e-108ae23fa0d6 highlighted

The Import tables find it by server and name. Each of the ten Import partitions starts the same way, with the lakehouse's SQL analytics endpoint and the database name SpaceParts. This is the Brands table:

Brands.tmdl open in VS Code from the spaceparts_project repository, with the semantic model folder and Brands.tmdl highlighted in the Explorer, and the source of the Brands partition, in import mode, highlighted: Sql.Database with the SQL analytics endpoint 77oajh3wezeejnmdlu54fth3om-mp2bmfx3rhbufhg2famatqlgfe.datawarehouse.fabric.microsoft.com and the database SpaceParts, then the brands table from the SpaceParts schema

2. A Successful Deployment That Still Read Dev

I selected all four items and deployed. The confirmation dialog listed all four as new.

The Deploy to this stage dialog for a deployment from SpaceParts Dev to SpaceParts Prod, listing New (4): the SpaceParts lakehouse, the Load SpaceParts data notebook, spaceparts_directlake_import_semanticmodel and spaceparts_report, with the Deploy button highlighted

The pipeline reported Successful deployment, and every item in Prod was now Same as source.

The pipeline after the first deployment, with the SpaceParts Prod stage showing Successful deployment, highlighted, and the notebook, lakehouse, semantic model and report all marked Same as source

The Prod lakehouse had new IDs, 26172069-a0ed-4c4a-8c61-a15715c9139e for the workspace and 0c495b60-7437-4a3b-a1f7-f3ab518bad6d for the lakehouse.

The SpaceParts lakehouse open in the SpaceParts Production workspace, with the new workspace ID 26172069-a0ed-4c4a-8c61-a15715c9139e and lakehouse ID 0c495b60-7437-4a3b-a1f7-f3ab518bad6d highlighted in the address bar, and the Explorer showing only an empty dbo schema under Tables

It was also empty. A deployment creates a new, empty lakehouse in the target workspace, as the Lakehouse git integration and deployment pipelines article describes, and in a real project the production lakehouse already has its data. So I leave that part here, because what matters in this writing is where the model reads from.

The lineage view of the Prod workspace showed where the Prod model was reading from. Its two inputs, a SQL analytics endpoint and a lakehouse, both carry the tag SpaceParts, the name of the Dev workspace. The Prod lakehouse sits further down with its own SQL analytics endpoint and the copied notebook, and nothing connects it to the model.

Lineage view of the SpaceParts Production workspace, where the semantic model's two inputs, a SpaceParts SQL analytics endpoint and a SpaceParts lakehouse, both carry a highlighted SpaceParts workspace tag, while the Prod lakehouse below feeds only its own SQL analytics endpoint and the Load SpaceParts data notebook

VS Code agreed. With the Dev repository on the left and the Prod repository on the right, expressions.tmdl was the same file in both, Dev IDs included.

Two VS Code windows side by side, spaceparts_project on the left and spaceparts_production on the right, each with expressions.tmdl open and the same two highlighted IDs, 1616f463-89fb-42c3-9cda-281809c16629 and a9779aaf-d8a9-4b22-898e-108ae23fa0d6, in the AzureStorage.DataLake URL

This is how deployment is meant to work. The Semantic model limitations section of The Microsoft Fabric deployment pipelines process says that when you deploy a Direct Lake semantic model, it doesn't automatically bind to items in the target stage, and that the model in the target stage still binds to the lakehouse in the source stage. The same paragraph suggests datasource rules to fix that. For my model, that route is closed. In the Considerations and limitations table of the Direct Lake overview, the row Deployment pipeline rules to rebind data source says Not supported for Direct Lake on OneLake, and the Compare storage mode capabilities table in the same article allows composite models with Import tables only on OneLake. The Import tables are what keep SpaceParts on OneLake, and being on OneLake is what rules out the rule.

The Semantic models table in Understand dependency binding in cross-workspace deployment gives the reason at file level. The Direct Lake connection string in expressions.tmdl contains a workspace-specific endpoint URL and database GUID, and the article says you need to replace them for cross-workspace deployment. Something had to replace them.

3. Rebinding by Hand Lasted Until the Next Deployment

That something was a notebook, rebind_lakehouse_semantic_model, and I ran it by hand in Prod first. It opens the model with sempy.fabric, replaces the Dev IDs in the Direct Lake URL with the Prod ones, points the Sql.Database lines of the Import tables to the Prod SQL analytics endpoint, and saves the model. This first version had the Prod workspace name typed into it.

The code came from AI. When I need to write a Fabric notebook like this, I sometimes ask AI to learn from semantic-link-labs, the open-source repository in Microsoft's GitHub organization that gives early access to new features for Semantic Link, and then suggest the code. That is how this notebook started.

The microsoft/semantic-link-labs repository on GitHub, with the repository name highlighted and the About panel describing it as early access to new features for Microsoft Fabric's Semantic Link

The rebind worked. The lineage view showed the Prod model reading the Prod SQL analytics endpoint, without the Dev tag.

Lineage view of SpaceParts Production after the hand-run rebind, with the semantic model now fed by the Prod SpaceParts SQL analytics endpoint, the highlighted Prod lakehouse in the middle, the Dev SpaceParts lakehouse with its SpaceParts tag on the far left, and the semantic model card highlighted

The Prod repository showed the same thing. In VS Code, expressions.tmdl on the Prod side now carried 26172069-a0ed-4c4a-8c61-a15715c9139e and 0c495b60-7437-4a3b-a1f7-f3ab518bad6d, the IDs from the Prod lakehouse's address bar.

The same two VS Code windows after the rebind, with expressions.tmdl in spaceparts_project still holding the Dev IDs and expressions.tmdl in spaceparts_production now holding 26172069-a0ed-4c4a-8c61-a15715c9139e and 0c495b60-7437-4a3b-a1f7-f3ab518bad6d, both highlighted

Then I deployed from Dev again, without a plan, and the lineage went straight back to the Dev workspace.

Lineage view of SpaceParts Production after a second deployment without a plan, with the semantic model's two inputs once again tagged with the SpaceParts Dev workspace, highlighted in green

That settled what I needed. A rebind done by hand in Prod lasts only until the next deployment. The step has to run inside every deployment, and running a step inside a deployment is what deployment plans are for.

4. Building the Plan, and a Notebook Prod Did Not Have

Deployment plans sit behind a tenant setting. In the Admin portal, Users can create deployment plan (preview) items was listed under Microsoft Fabric with a New badge, and I enabled it for the entire organization. The Enable deployment-plan creation for your tenant section of Create a deployment plan in Microsoft Fabric walks through the same setting.

The Admin portal tenant settings with Users can create deployment plan (preview) items under Microsoft Fabric marked New, its toggle set to Enabled for the entire organization, and the Apply button highlighted

A plan is a workspace item, so I created one in the Dev workspace from New item, where searching for deploy shows Deployment Plan (preview).

The Dev workspace SpaceParts, highlighted, with its items Synced, and the New item panel searched for deploy, showing Deployment Plan (preview), highlighted, described as a plan to define dependencies and actions that run before and after each item deploys

I named it DeploymentPlan_SpaceParts and kept it in the SpaceParts workspace.

The New Deployment Plan dialog over the SpaceParts workspace, with the name DeploymentPlan_SpaceParts, the location SpaceParts, and the Create button highlighted

The canvas lists the workspace items on the left, and each one has Add to canvas in its menu.

The empty DeploymentPlan_SpaceParts canvas, with Build your deployment plan listing the workspace items on the left, and the semantic model highlighted with its menu open on Add to canvas

I added the semantic model, which became a deployment group with a Deploy box in the middle and two empty slots around it, Actions before and Actions after. Selecting Actions after opened a panel where Add action offered only the two notebooks, and I picked rebind_lakehouse_semantic_model.

The DeploymentPlan_SpaceParts canvas with one group for the semantic model, a Deploy box between empty Actions before and Actions after slots, and the Actions after panel open with Add action listing two notebooks, Load SpaceParts data and the highlighted rebind_lakehouse_semantic_model

Only notebooks showed up because a plan can run only a few item types. The Item types you can run as an action section of Deployment plan actions in Microsoft Fabric lists notebooks, data pipelines, Dataflow Gen2, copy jobs and user data functions, all with the job type Execute. A plan can deploy the lakehouse, the model and the report, but it can't run them.

I saved the plan and went to the pipeline, where a new with plan picker now sits next to Deploy from. I chose DeploymentPlan_SpaceParts. In the list, the lakehouse and the model were Same as source, and the plan and the rebind notebook were Only in source, because neither existed in Prod yet. I had selected the lakehouse and the model, but not the notebook.

The pipeline with the with plan picker open and DeploymentPlan_SpaceParts highlighted, the SpaceParts lakehouse and the semantic model selected and marked Same as source, and the deployment plan and the rebind_lakehouse_semantic_model notebook unselected and marked Only in source

The confirmation dialog listed one new item, the plan.

The Deploy with plan dialog for DeploymentPlan_SpaceParts, Copied from source, with New (1) listing only DeploymentPlan_SpaceParts, highlighted, over the pipeline list where the rebind_lakehouse_semantic_model notebook is Only in source

When I clicked Deploy, I got this instead of a deployment.

A dialog titled Deployment plan has a missing item reference, saying the action rebind_lakehouse_semantic_model_SynapseNotebook references an item, 9dcc4ee5-91a5-4d4b-bc8f-5f7e629a456a, that doesn't exist, over the pipeline item list

The action "rebind_lakehouse_semantic_model_SynapseNotebook" references an item ("9dcc4ee5-91a5-4d4b-bc8f-5f7e629a456a") that doesn't exist. This one is fair, and it is documented. The Determine the deployment scope section of What is a deployment plan in Microsoft Fabric? says that attaching a plan doesn't automatically select the items it references, and that the items the plan's actions need must be available in the target workspace when those actions run. My action wanted to run a notebook Prod did not have, and I had not asked the pipeline to bring it.

I selected the notebook too.

The pipeline with the SpaceParts lakehouse, the semantic model and the rebind_lakehouse_semantic_model notebook selected, their checkboxes highlighted, the notebook still Only in source with its source item name highlighted, and the Deploy button showing 4

The dialog now said the plan was Copied from source and listed two new items, the plan and the notebook.

The Deploy with plan dialog for DeploymentPlan_SpaceParts, Copied from source, listing New (2), DeploymentPlan_SpaceParts and rebind_lakehouse_semantic_model, highlighted, with the rebind notebook now selected in the list behind it

5. Same as Source, Then a Failed Deployment That Still Deployed the Model

That deployment succeeded. The plan and the rebind notebook arrived in Prod, and the model still read Dev.

Lineage view of SpaceParts Production after the first deployment with the plan, with DeploymentPlan_SpaceParts and rebind_lakehouse_semantic_model now in the workspace, and the semantic model still fed by the SQL analytics endpoint and lakehouse tagged SpaceParts

Looking back at the dialog, the model was never in it. It was selected, but it was Same as source, and the dialog listed only the two new items. My reading is that the model's group had nothing to deploy, so its post-deployment action never ran. The Execute deployment groups and actions part of the plan overview describes the order inside a group, pre-deploy actions first, then the item, then post-deploy actions, but it doesn't say what happens to a group whose item has nothing to deploy. So that part is my interpretation of what I saw, not something the article states.

To give the group something to do, I changed a small thing in the Dev model, and the pipeline marked it Different from source.

The pipeline with DeploymentPlan_SpaceParts selected in the with plan picker, every item Same as source except the semantic model, which is selected and marked Different from source, and the Deploy button showing 1

This deployment failed with Something went wrong. Deployment couldn't be completed.

A Something went wrong dialog saying Deployment couldn't be completed, with a See details link and a Close button, over the pipeline where the SpaceParts Prod stage card shows Failed deployment

The stage card said Failed deployment. Yet the model in the list had turned to Same as source, which means it was deployed.

The SpaceParts Prod stage card showing Failed deployment, highlighted, while the semantic model in the list below is now marked Same as source, also highlighted

Both halves of that are documented. The If an operation fails section of the plan overview says the operation stops when an item or action fails and doesn't roll back completed work, and the Limitations during a deployment list adds that items already deployed stay in the target workspace while later items don't deploy. The pipeline view shows that the failure came after the model was deployed, not which step it was. The An action failed section of Troubleshoot deployment plans in Microsoft Fabric explains where to look: an action is a normal Fabric item run, so its failure details are in that item's run history, not in the deployment.

The lineage view still showed the Dev workspace on both of the model's inputs.

Lineage view of SpaceParts Production after the failed deployment, with the semantic model's two inputs, a SQL analytics endpoint and a lakehouse, both still carrying a highlighted SpaceParts workspace tag, and DeploymentPlan_SpaceParts in the workspace

That is the state a deployment without rollback can leave behind: a new model definition in Prod, still pointing at Dev. At this point I thought the plan itself was not right.

6. Which Way the Arrow Points

Next I gave the notebook a deployment group of its own, so that the plan would deploy it too. On the canvas, a line from the bottom of one group to the top of another means the second group depends on the first. My first attempt put the model on top and the notebook underneath.

The plan canvas with the semantic model group on top and the rebind_lakehouse_semantic_model group underneath, joined by a highlighted arrow from the bottom of the model group to the top of the notebook group, and both Actions after slots empty

That arrow says the notebook group waits for the model group. In plan.yml it becomes a dependsOn entry on the notebook's group that names the model's group, and the Understand the plan.yml structure section of Deployment plan examples in Microsoft Fabric is clear that group order comes from dependsOn, not from where a group sits in the file. So this plan deploys the model first and the notebook second, which is backwards for what I needed, and the same article gives two reasons. The Validate before anything deploys section says an action can only run an item that's already deployed, so the item an action runs has to be deployed by an earlier group. And the Refresh content after it deploys section says a deployment updates item definitions and doesn't run anything, so deploying the notebook after the model doesn't run it either.

I changed the Dev model once more and deployed with this plan. Because the plan had changed too, the pipeline marked both the plan and the model Different from source, and I selected both.

The pipeline with DeploymentPlan_SpaceParts in the with plan picker, highlighted, and the deployment plan and the semantic model both selected and marked Different from source, highlighted, with the Deploy button showing 2 and the Prod stage card still showing the earlier Failed deployment

It took a few more rounds with AI before the design settled. The final canvas turns the arrows the other way.

The final plan canvas, with the SpaceParts lakehouse group and the rebind_lakehouse_semantic_model group side by side at the top, both arrows leading into the semantic model group, whose Actions after slot holds Run action on rebind_lakehouse_semantic_model, and the spaceparts_report group at the bottom

The lakehouse and the notebook each get a group at the top, and neither depends on the other. Both arrows lead into the model's group, so the model deploys only after both of them, and its Actions after slot holds Run action on rebind_lakehouse_semantic_model. The report's group waits for the model's. This is the same plan as it sits in my Dev repository, in DeploymentPlan_SpaceParts.DeploymentPlan/plan.yml:

plan.yml of DeploymentPlan_SpaceParts.DeploymentPlan open in VS Code, with the folder and plan.yml highlighted in the Explorer, listing four groups: SpaceParts_Lakehouse, rebind_lakehouse_semantic_model_SynapseNotebook, spaceparts_directlake_import_semanticmodel_dataset with dependsOn on the first two and a postActions entry that runs the notebook with job type Execute and logicalId 39b282de-db91-4e27-86b4-610786a48ace, and spaceparts_report_Report depending on the model's group

Three details in this file are easy to miss. The canvas gave each group the item's name plus a type suffix, so the notebook's group is rebind_lakehouse_semantic_model_SynapseNotebook and the model's is spaceparts_directlake_import_semanticmodel_dataset, old type names included. The notebook's logical ID, 39b282de-db91-4e27-86b4-610786a48ace, appears twice: once as its own group, which deploys it, and once under postActions, which runs it. It is the same logicalId as in the notebook's .platform file, and the Deployment plan definition article describes job.logicalId as the logical ID of the item whose job is run. And although the lakehouse and notebook groups don't depend on each other, the Limitations during a deployment list in the plan overview says independent groups can't deploy in parallel, so Fabric still takes them one at a time.

7. A Notebook That Only Knows Its Own Workspace, and No Refresh

The plan was half of the redesign. The other half was the notebook, and it took several iterations and trials with AI before it was ready to run inside a deployment. I won't walk through the code here. What I want to share is what I had to ask AI to check and fix, because those points matter more than the code itself:

  • No hard-coded workspace. The first version had the Prod workspace name typed into it. The notebook now asks the runtime which workspace it is running in, and finds the lakehouse by name in that same workspace. That makes it the same notebook in every stage: in Dev it finds nothing to change and saves nothing, and in Prod it finds the Dev IDs and replaces them.
  • Both kinds of tables. The Direct Lake URL in expressions.tmdl and the Sql.Database lines of the Import tables both have to point to Prod, or the model ends up reading from two workspaces.
  • Nothing to install. I removed a %pip install semantic-link-labs line. Everything the notebook uses is in sempy, which ships with Fabric, so the action doesn't install a library while a deployment waits for it.
  • Stop before saving. The notebook runs inside a deployment with nobody watching it. If a table is missing in the target lakehouse, or a source would still point to another lakehouse after the rebind, it raises an error and saves nothing.
  • No parameters. The Pass parameters to an action section of the actions article says a plan passes parameter values through to the item and points to each item type's documentation for which parameters it accepts. I didn't find how a notebook action receives them, so the notebook needs none.
  • No refresh. This one took the longest, so it gets the rest of this section.

The first deployment with the redesigned plan failed anyway. The rebind succeeded and the refresh at the end of the notebook did not, which failed the action, and a failed action failed the whole deployment, so the report's group never ran.

The refresh failed with Premium_ASWL_Error, and the message said the model uses a default data connection without explicit connection credentials. When I first saw it, the notebook was refreshing over XMLA, so I blamed XMLA and switched the refresh to the REST API. The error stayed exactly the same, so the transport was never the problem. Rebinding and refreshing are different kinds of work. A rebind edits the model definition, and saving a definition needs no credentials for the data. A refresh reads the sources, and in Prod they were on the default single sign-on connection.

The Key concepts and terminology and Connection configuration sections of Integrate Direct Lake security describe both options: the default SSO configuration usually works, and you can also bind a Direct Lake model to an explicit cloud connection to provide a fixed identity. Mapping the Prod model's data sources to explicit cloud connections, in the model's Settings under Gateway and cloud connections, is what made the hand-run refresh succeed. A deployment does not carry that mapping. The Item properties that are not copied section of the deployment pipelines process article lists data source credentials among the semantic model properties that aren't copied, and the plan overview says a plan doesn't deploy workspace-level configuration such as connections and gateway bindings.

What I did not expect, and found no documentation for, is that each deployment also reset the connection mapping I had made in Prod. During a deployment the model briefly pointed back at Dev, then the notebook pointed it at Prod again, and the refresh inside the notebook met the same missing connections as before.

So I took the refresh out of the notebook. The next deployment succeeded, and after it I mapped the connections in Prod and refreshed the model by hand. The lineage view finally showed what I had wanted since the first deployment: the Prod model reading the Prod lakehouse and its SQL analytics endpoint, with nothing from the Dev workspace in the picture.

Lineage view of SpaceParts Production after the successful deployment, with the highlighted Prod SpaceParts lakehouse feeding the SpaceParts SQL analytics endpoint and the highlighted semantic model, then spaceparts_report, and no item from the Dev workspace in the picture

8. From a DevOps Standpoint: Three Kinds of Work in One Deployment

From a DevOps standpoint, this experiment split one deployment into three kinds of work: what the pipeline copies, what the plan runs, and what someone still does by hand in Prod.

Code review. plan.yml is short enough to review line by line, and two checks would have caught both of my mistakes. First, read dependsOn as "waits for". Every item an action runs has to be in the target workspace before the action starts, either because a group that the action's group waits for deployed it, or because it is already there from an earlier deployment. Second, compare the action's job.logicalId with the logicalId in that notebook's .platform file. If they match, the action runs the notebook you think it runs. A changed plan also shows up in the pipeline as Different from source, like any other item, so it can be reviewed before it reaches Prod.

Version control. Each workspace has its own repository, and after a successful run the two disagree on purpose. expressions.tmdl holds the Prod IDs in the Prod repository and the Dev IDs in the Dev repository, so any comparison between the two will always show that file, and that difference is correct. The plan lives in the Dev repository as DeploymentPlan_SpaceParts.DeploymentPlan/plan.yml and reaches Prod as an item, the same way the notebook does. One thing I have not settled: the rebind is a change made in the Prod workspace, and the Source control button in the last lineage screenshot shows two changes waiting. I have not checked which two items they are, and whether the Prod repository should receive the rebound model as a commit after every deployment is a decision I still have to make with my team.

Automation. The manual step left is the connection mapping, and it is also the step that would let the refresh go back into the notebook. The Items - Bind Semantic Model Connection REST API binds a semantic model data source reference to a data connection. Its Limitations section says it doesn't support bulk operations, so SpaceParts, with a OneLake source and a SQL analytics endpoint, would need a request for each, and its Permissions section says the caller must be the owner of the semantic model. I have not tried it yet, and it is the follow-up I want to write next.

Two questions stay open, and both matter before you run this on a model people depend on. The documentation doesn't say which identity runs a post-deployment action, and my notebook needs to read the old lakehouse and write to the target model. It also doesn't say what happens to a group whose item is in the plan but has nothing to deploy, which is the situation behind section 5. I would test both on workspaces nobody uses before trusting a plan with production.

A Note on Working with AI

The division of work was the usual one. AI wrote the notebook code, first from what it learned in semantic-link-labs and then through the iterations in section 7. I ran every deployment, built the plan on the canvas, and took every screenshot. AI was quick to write a rebind. Making it safe to run inside a deployment took the points in the section 7 list, and I had to ask for each of them.

What made the result trustworthy was not the AI but the evidence around it: the lineage view, the two repositories side by side in VS Code, and the pipeline's own comparison column, none of which the AI produced. The one time those disagreed, a lineage view that looked rebound next to a refresh that kept failing, was the moment I learned the difference between a rebind and a refresh.

Closing Thoughts

I expected a deployment plan to make Direct Lake follow the model to Prod. It doesn't do that, and it was never meant to. The mental model I am keeping is this: a deployment pipeline copies the model exactly as it is, and a deployment plan is the place inside every deployment where I run the step that points the copy at Prod.

There is a lot I did not test. I only went from Dev to Prod, with one model, one lakehouse and two stages. I never tried a pre-deployment action, a Variable Library reference, or a plan attached through Git integration instead of a pipeline. And the connection mapping is still a manual step after every deployment, so this setup is working, but it is not finished.

The cost so far is four deployment groups, one post-deployment action, one notebook that knows only its own workspace, and two steps by hand after every deployment: map the connections, then refresh.

I hope this helps having fun in exploring deployment plans and embracing this new era of Fabric deployments that can do more than copy!