Development Documentation
View as:

Semantic model data connections

Every Direct Lake semantic model in every workspace is bound to a shareable cloud connection that authenticates as sp-fabric-platform-admin. This is the fixed-identity pattern — at query time, data access runs as the SPN, not as the viewer. Developers open any model and it works, without needing a role on the underlying warehouse.

There is one SCC per environment / warehouse (DEV, UAT, PROD, and each feature env). Binding requires the SCC's server + database to match the model's M expression exactly, and each env has its own Gold Warehouse GUID — so a single global SCC can't bind feature models.

Why this exists

Direct Lake defaults to SSO. Under SSO, the viewer's identity is checked against the SQL analytics endpoint. Developers (members of FP GER Fabric Developers) have no direct role on DEV-Gold, so SSO queries fail and Fabric falls back to DirectQuery — every table shows the warning "Only DAX queries may fall back to DirectQuery" and visuals degrade.

Ownership doesn't matter at query time — only the effective identity the connection uses.

The per-env connection

One SCC per env, created on demand and reused across every deploy of that env:

FieldValue
Namefabric-dev-gold-warehouse-fixed (DEV) · fabric-feat-<name>-gold-warehouse-fixed (feature) · analogous for UAT/PROD
TypeSQL (Shareable Cloud)
ServerThe env's Gold Warehouse SQL analytics endpoint (from deployment/<env>.ymlconnection_overrides.sql_database.server)
DatabaseThe env's Gold Warehouse GUID (from connection_overrides.sql_database.database_id)
Credentialssp-fabric-platform-admin (ServicePrincipal)
SSOdisabled
EncryptionEncrypted

The SPN is Admin on every Gold Warehouse, so it can read whichever env it's pointed at. All semantic models bound to their env's connection query through the SPN's identity, and developers need zero direct access to the warehouse workspace.

When the binding happens

  • New feature envscripts/fabric dev start calls fabric_connections.py bind after fabric-cicd deploy. No manual step.
  • DEV → one-time retrofit already applied. New DEV deploys keep the binding because fabric-cicd uses workspace-Admin (not ownership) to update definitions; ownership stays on the SPN.
  • Manual re-bindbash scripts/fabric dev bind-connections <feature-name|dev>.

Models with no SQL data source (static DATATABLE slicers, import-mode) are automatically skipped.

Ownership strategy

  • Model owner: sp-fabric-platform-admin. Durable — fabric-cicd deploys do not change ownership.
  • Query-time identity: same SPN, via the fixed-identity connection.
  • User access: Build permission on the semantic model. No workspace role on DEV-Gold required.

If a model was previously owned by a user, the binder calls the Power BI Takeover API (POST /v1.0/myorg/groups/{ws}/datasets/{id}/Default.TakeOver) before binding, so the SPN can configure the connection.

Recycling and stale-connection audit

DEV/UAT/PROD SCCs are durable and reused across deploys. Feature-env SCCs live as long as the feature env does — scripts/teardown_feature_env.sh only touches workspace-scoped items (warehouse, lakehouse, shortcuts, role assignments, workspace git connection), so orphaned feature SCCs accumulate over time and should be pruned periodically.

To audit connections that aren't referenced by any item (drift from manual UI creation):

bash scripts/fabric dev connections              # list all
python scripts/fabric_connections.py prune       # show unreferenced

prune never auto-deletes. Review the list, then delete via the Fabric UI (Manage connections and gateways) or a one-off REST call.

Adding a new data source

The per-env SCC covers that env's Gold Warehouse (SQL endpoint). If a new Direct Lake model references a different source (e.g. a Bronze lakehouse SQL endpoint), create a second SCC with the same pattern — same naming convention, SPN credentials, SSO off — and extend fabric_connections.py to try both when binding.

Troubleshooting

SymptomCheckFix
Warning on every table in Fabric UIModel's binding in Settings → Gateway and cloud connectionsRe-run fabric dev bind-connections <env>
BindNotModelOwner errorModel is owned by another userThe binder auto-takes-over; if it still fails, check SPN permissions on workspace
BindConnectionDetailNotFound on a feature envBinder was pointed at the wrong env's SCC (server/database_id mismatch with the model's M expression)Re-run fabric dev bind-connections <feature-name> — it now passes --env feat-<name> so the SCC matches the env's warehouse.
FAIL — all N model(s) skipped, none boundRegression guard: the SCC's server+database didn't match any model. Almost always an --env / config mismatch.Verify deployment/<env>.yml's connection_overrides.sql_database.{server,database_id} matches the actual feature warehouse, then re-run.
BindConnectionDetailNotFound on a Gold modelModel references a different data source than Gold (e.g. Bronze lakehouse, import mode)Expected — skipped. Add a new SCC if needed.
Connection missing entirelyInitial bootstrap failedpython scripts/fabric_connections.py ensure --env <dev|feat-name|uat|prod>