← All Adapters

MICROSOFT FABRIC

Fabric warehouses and lakehouse SQL endpoints are first-class engines in DVT: make one your default target and run a whole dbt project against it, or point meta.connection at it and read its tables live inside cross-engine federation models. Fabric is the Entra-only member of the SQL Server family — same TDS protocol as its SQL Server sibling, but you always sign in with Entra ID, never a SQL password.

A COMPLETE PROFILES.YML

The most common setup for pipelines — an Entra service principal (an app registration, not a person). Copy it, change the endpoint and warehouse name, point the three env vars at your registration, and you're connected:

# ~/.dbt/profiles.yml
my_project:
  target: fabric_prod
  outputs:
    fabric_prod:
      type: fabric
      server: abc123xyz.datawarehouse.fabric.microsoft.com
      database: my_warehouse        # warehouse or lakehouse SQL endpoint name
      schema: dbo
      authentication: ServicePrincipal
      client_id: "{{ env_var('AZURE_CLIENT_ID') }}"
      tenant_id: "{{ env_var('AZURE_TENANT_ID') }}"
      client_secret: "{{ env_var('AZURE_CLIENT_SECRET') }}"
      encrypt: true                 # Fabric requires TLS — always set this
      threads: 4

The servervalue is your workspace's SQL connection string — in Fabric, open the warehouse (or lakehouse SQL endpoint), choose Settings → SQL connection string, and copy it. Give the service principal access to the workspace (or the specific item) in Fabric before the first run, or the sign-in succeeds and the database lookup fails.

Then run dvt sync once from your project. It reads this profile, sees a Fabric output, and installs the adapter and the pyodbcdriver for you. One OS-level prerequisite remains yours: the unixODBC runtime and Microsoft's msodbcsql ODBC driver (on macOS, brew install unixodbc plus Microsoft's driver package). dvt sync checks for this and names the fix if it's missing; dvt debug confirms the connection end to end.

WHY ENCRYPT: TRUE IS SPELLED OUT

The SQL Server family's defaults are tuned for local dev containers — encrypt defaults to false. There is no local Fabric, and the real endpoint requires TLS, so on a type: fabric output always write encrypt: trueyourself. Fabric's certificate is a real one, so the family's trust_cert default is fine to override too: trust_cert: false makes the driver actually verify it.

ENTRA ID PASSWORD — ACTIVEDIRECTORYPASSWORD

For working interactively as yourself, use your organizational account as the user and password:

    fabric_dev:
      type: fabric
      server: abc123xyz.datawarehouse.fabric.microsoft.com
      database: my_warehouse
      schema: dbo
      authentication: ActiveDirectoryPassword
      user: analyst@yourcompany.com
      password: "{{ env_var('ENTRA_PASSWORD') }}"
      encrypt: true
      trust_cert: false

Accounts behind MFA typically can't authenticate this way — the password grant has no second-factor step. That's the usual reason to switch to a service principal even for development.

WHAT FABRIC DOES NOT ACCEPT

No SQL auth. Fabric has no SQL logins. A profile with plain user/password and no authentication line is treated as SQL auth — the family default — and Fabric's endpoint refuses the sign-in. If you hit a login failure with a working password, this is almost always the missing line: set authentication: ActiveDirectoryPassword.

No Windows integrated auth. windows_login exists in the shared SQL Server family, but a SaaS endpoint has no domain trust to lean on — leave it out on Fabric outputs.

HOW FABRIC BEHAVES IN DVT

database is the item, schema is dbo. database names the warehouse or lakehouse SQL endpoint — the thing you opened in the workspace — and schema defaults to dbo, where Fabric puts tables unless you've created schemas of your own.

Lakehouse SQL endpoints are read-only.A lakehouse's SQL endpoint serves queries, not DDL — so it works as a federation source, while models should build into a warehouse. If you're doing both, that's simply two outputs in profiles.yml, one per item.

Reading Fabric live from a federation model takes one meta.connection line pointing at the output you defined above — the classic pairing is Fabric next to an on-prem engine like Oracle in one model:

# models/staging/sources.yml
sources:
  - name: fabric_data
    meta:
      connection: fabric_prod   # a profiles.yml output name
    schema: dbo
    tables:
      - name: sales
      - name: inventory

INCREMENTAL MODELS — MERGE, AND TWO DELETE MODES IT ALONE ALLOWS

The Fabric adapter accepts four strategy names, spelled exactly as they go into config: append, delete+insert, merge, and microbatch. insert_overwrite is not among them — a helper macro for it exists in the adapter, but the name is rejected before that macro can be reached.

Leave incremental_strategy unset and the adapter runs its default, which branches on the key: with a unique_key it emits a MERGE, without one it appends. Fabric is the one engine in the SQL Server family with extra merge-time behaviour you can ask for — two ways of deleting from the target as part of the same run:

{{ config(
    materialized='incremental',
    incremental_strategy='merge',   -- append | delete+insert | merge | microbatch
    unique_key='sale_id',
    delete_condition="DBT_INTERNAL_SOURCE.is_deleted = 1"
) }}

select sale_id, amount, is_deleted, updated_at
from {{ source('fabric_data', 'sales') }}
{% if is_incremental() %}
where updated_at > (select max(updated_at) from {{ this }})
{% endif %}

delete_condition runs a separate delete after the MERGE, joining target to source on the unique_key and removing the rows your condition matches — the shape to use when the source carries a soft-delete flag. Both DBT_INTERNAL_SOURCE and DBT_INTERNAL_DEST are available as aliases inside the condition. delete_not_matched_by_source is the other mode: it deletes target rows whose key has no match in the source at all, for models that return the complete current dataset rather than a delta.

Both are merge-only, and the check is on the literal string — leaving incremental_strategy unset raises too, even though the default routes to a merge when a key is present. They are also mutually exclusive. All three refusals are compile-time, which means you find out before any SQL runs:

delete_condition requires incremental_strategy: merge, got 'default'
delete_not_matched_by_source requires incremental_strategy: merge, got 'append'
delete_condition and delete_not_matched_by_source are mutually exclusive
  — use one or the other

DELETE_NOT_MATCHED_BY_SOURCE NEEDS A UNIQUE_KEY

Without one, the generated MERGE matches nothing and still emits when not matched by source then delete — which is every pre-existing row in the target. Nothing raises. Treat unique_key as required whenever you set this config.

The other key-shaped surprises. delete+insert without a unique_key silently degrades to an append — the delete block is skipped and the insert still runs, with no error. merge without a unique_key compiles to a MERGE whose match predicate is FALSE and which carries no update clause, so every incoming row is inserted and nothing is updated. microbatch needs an event_time config and the batch boundaries dbt passes with it, and ignores unique_key entirely.

None of this is gated on a Fabric version, on a table format, or on whether you point at a warehouse or a lakehouse SQL endpoint — the adapter declares no such conditions in the incremental path. What does apply is the earlier rule on this page: a lakehouse endpoint serves queries rather than DDL, so build incrementals into a warehouse. Strategies also never run on a full refresh or against an existing view; the model is simply rebuilt.

A name the adapter does not accept is refused by dbt's own gate rather than by the adapter, and the message depends on the kind of name you wrote:

incremental_strategy='insert_overwrite'
  The incremental strategy 'insert_overwrite' is not valid for this adapter

incremental_strategy='upsert'
  dbt could not find an incremental strategy macro with the name
  "get_incremental_upsert_sql" in <your project>

When Fabric is the target of a federated model. An f_incremental model is computed by DVT and landed through its data-movement layer, so the vocabulary narrows to append, merge, and delete+insert; insert_overwrite and microbatch are refused as DVT025— "has no Sling equivalent — f_incremental supports append, merge and delete+insert". Fabric's two delete configs are adapter macros, so they belong to the native lane only. On the federated lane merge and delete+insert collapse into the same key-based upsert on unique_key, either one without a key warns and falls back to a full refresh rather than failing, and append without a watermark_column does the same. One refusal is specific to this engine: Fabric is not in the keyless-watermark allow-set, so an f_incremental that leans on a watermark instead of a unique_key is refused here with DVT026. DVT has verified that path on Postgres, Redshift, MySQL, DuckDB, SQLite, SQL Server, Oracle, ClickHouse, and Trino, and refuses it everywhere it has not — Fabric alongside StarRocks, Snowflake, Databricks, BigQuery and Athena. Give the model a unique_key and the ordinary merge lane applies.

REFERENCE — EVERY PROFILE FIELD

Everything a type: fabricoutput reads. The fields are the SQL Server family's — with Entra auth doing all the signing in.

FIELDTYPEREQUIREDDEFAULTNOTES
typestringyesMust be fabric.
serverstringyesThe workspace SQL connection string (…datawarehouse.fabric.microsoft.com). host is an accepted alias.
portintegerno1433Fabric listens on the standard TDS port — you'll rarely write this.
databasestringyesWarehouse or lakehouse SQL endpoint name.
schemastringnodboDefault schema for models.
authenticationstringyesActiveDirectoryPassword, ServicePrincipal, or ActiveDirectoryServicePrincipal (same thing). Fabric is Entra-only — leaving it unset means SQL auth, which Fabric refuses.
userstringsee notesRequired with ActiveDirectoryPassword — the Entra sign-in (user@domain). Unused with a service principal.
passwordstringsee notesPartner of user — same rules. Keep it in env_var().
client_idstringsee notesRequired for service principal auth — the app registration's client id.
tenant_idstringsee notesRequired for service principal auth — the Entra tenant id.
client_secretstringsee notesRequired for service principal auth. Keep it in env_var().
encryptbooleannofalseFamily default is false (local-dev tuning) — always set true on Fabric; the endpoint requires TLS.
trust_certbooleannotrueSet false on Fabric so the real certificate is verified.
windows_loginbooleannofalseExists in the shared SQL Server family; not usable against Fabric — leave it out.
threadsintegerno4Parallel model threads when Fabric is your default target.