The five patterns differ in what carries work to production. Everything else is the same across all five, and everything else is where an estate comes apart.
1. Nothing carries your credentials
Not git, not deployment pipelines, not fabric-cicd, not a notebook over REST. In every pattern, somebody has to bind the connections in the target environment. Decide who that is up front, and write down which environment they do it in and how they will know it worked.
Credentials are one of the things a deployment leaves behind.The deployment pipelines page has the full list, and what does travel with it. It applies to all five patterns, because it describes what an item definition holds rather than what moves it.
2. Pick one lever for per-environment configuration
There are four mechanisms. Pick one. Using more than one in the same solution is how an estate becomes unmaintainable.
| Mechanism | Pattern | Lives in | Survives workspace reassignment | Reviewable |
|---|---|---|---|---|
| Power Query parameters, changed in Desktop | Pro, manual | The file | Yes | Only if the file is in a repository |
| Deployment rules | Pipelines | The target stage, on the item, owned by a person | No | No |
| Variable Library | Pipelines and git | A workspace item with its own lifecycle | Yes | Partly |
parameter.yml | Git and mixed estate | The repository | Yes | Yes, it is a reviewed file |
3. Verify by value, not by status
Every pattern can deploy the wrong environment's data and tell you it worked. A status code says the operation finished, and nothing about whether it did the right thing. I pointed a target at the wrong endpoint and it deployed, refreshed and came back green at every step.
The fix is cheap. Give each environment a number that differs, a row count or a total, and check it after every deployment. If you are promoting by hand, that is a card on the report canvas and a person looking at it. If a script is doing the promoting, it is a DAX query in the script. Same idea either way.
4. Name things so the environment is unmissable
- The environment goes in the workspace name, as a suffix, so sibling environments sort together.
- Item names do not carry the environment. Deployment pipelines pair items by name and type, so
Sales_Devin Dev andSales_Prodin Prod are two unrelated items, and deploying creates a duplicate instead of overwriting. The naming guide allows anENVprefix on an item, but only where items from two environments sit in the same workspace. That is never true of a workspace inside a pipeline. - Nothing starts life outside Dev. Every item is created in development and reaches the other environments by being deployed. An item you create directly in Test has nothing to pair with, and will quietly duplicate.
The rest of the convention, covering every item type and every pipeline activity, is in the naming guide.
One model, several reports
One semantic model with several reports connected live to it is how most Power BI estates are built. A live connection is not a setting on the workspace. It is written inside the report, and it names the workspace and the model it points at, so moving a report between environments means rewriting it. Every pattern has to do that. They differ in who does it.
| Pattern | What rebinds the report | What that means |
|---|---|---|
| One workspace | Nothing to rebind | There is one environment, so the report can only point at the model beside it. |
| Three Pro workspaces | You, by hand, per report | Publishing a live-connected report into Test does not repoint it. It keeps reading the model it was authored against. |
| Deployment pipelines | The pipeline, per report | Every report on the model is rebound, including one deployed on its own with the model already in place. |
| Git and build | The build, per report | fabric-cicd rewrites the reference as it publishes, so it is code you own rather than a service behaviour. |
| Mixed estate | Your deploy script, per report | The notebook rewrites definition.pbir. Six reports on one model is six rewrites. |
The failure this creates is the same one in every pattern, and it is quiet. A report pointing at the wrong environment’s model opens, renders and refreshes. Every status is green and the numbers are real. They belong to the wrong environment. That is the same fault the section above is about, which is why an anchor value per environment is the check that catches it, whoever did the rebinding.
Moving between patterns
From manual Pro workspaces to deployment pipelines, the thing that catches people is assigning all three existing workspaces straight into pipeline stages without first checking how the items pair up. You get duplicates instead of a release process. Assign Dev only, then deploy forward into empty stages.
From the mixed estate back to pipelines is the good outcome. Write it into the design from the start: once every reporting workspace can sit on capacity, the deployment notebook is deleted and the pipeline takes over. Agree that in advance, because by then somebody will have grown attached to the notebook.
Pre-flight checklist, whichever pattern you chose
- Every environment’s workspace type and capacity assignment is written down
- One configuration mechanism chosen, and only one
- Connections and credentials: who binds them, where, and how success is confirmed
- An anchor value per environment, and something that checks it
- Workspace roles set by group, not by individual
- Consumers reach production through an app, not through the workspace
- Refresh schedules exist in the target, because they do not deploy
- Row-level security role membership assigned in the target, because it does not deploy
- Somebody other than the author can perform the deployment
Frequently asked questions
- Does a deployment pipeline really need capacity on every stage, or only on production?
- Every stage. Microsoft’s own limitation is that the workspace must reside on a Fabric capacity, with no exception for the earlier stages. It is the fact the whole mixed estate pattern exists because of.
- Does Premium Per User count as capacity for pipelines?
- Partly, and confusingly. With PPU the workspace is automatically associated with your PPU and permissions are not required, so pipelines are usable. But a PPU workspace can only be accessed and consumed by other PPU users, and PPU does not provision a Fabric capacity, so non-Power BI Fabric items still will not run. Usable for a Power BI team where everyone has PPU. Not a general answer.
- Do Direct Lake models rebind when deployed with their lakehouse?
- No, and it is the one exception where you would most expect rebinding to work. The deployment pipelines page has what to do about it.
- Are PBIR reports deployable through pipelines?
- Microsoft documents them as unsupported. One deployed cleanly for me anyway, arriving in the target stage paired to its source. I would still write the documented answer into a contract, and I would test my own reports before dropping this pattern over that line.
- Is the missing-credential problem a Pro problem?
- No. The same model on a capacity failed in exactly the same way until the connection was bound. It is a property of import models created through the API, not of the licence.
- Can the mixed estate path be made unattended?
- Not with a user identity, because creating an OAuth2 connection needs a browser redirect. A service principal can, and that path runs start to finish with no portal step.
Sources
Everything on these pages is either Microsoft's documentation, linked below, or something I ran myself in throwaway workspaces in my own tenant in September 2026. Where a page says I tried something, that is what it means.
- Overview of Fabric deployment pipelines(opens in a new tab)
- The Fabric deployment pipelines process(opens in a new tab)
- Get started using deployment pipelines(opens in a new tab)
- Create deployment rules(opens in a new tab)
- Understand Microsoft Fabric licences and capacity(opens in a new tab)
- Data refresh in Power BI(opens in a new tab)
- Best practices for lifecycle management in Fabric(opens in a new tab)
- Introduction to git integration(opens in a new tab)
- Git integration process(opens in a new tab)
- fabric-cicd on PyPI(opens in a new tab)
- fabric-cicd documentation(opens in a new tab)
If you would rather watch than read, four Fabric Field Notes videos(opens in a new tab) cover the same ground: what a deployment pipeline is, git against deployment pipelines, why deployment rules only work on the second deploy, and why git sync is not deployment.