← 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 config.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 config.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
    config:
      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
typestringyes—Must be fabric.
serverstringyes—The 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.
databasestringyes—Warehouse or lakehouse SQL endpoint name.
schemastringnodboDefault schema for models.
authenticationstringyes—ActiveDirectoryPassword, ServicePrincipal, or ActiveDirectoryServicePrincipal (same thing). Fabric is Entra-only — leaving it unset means SQL auth, which Fabric refuses.
userstringsee notes—Required with ActiveDirectoryPassword — the Entra sign-in (user@domain). Unused with a service principal.
passwordstringsee notes—Partner of user — same rules. Keep it in env_var().
client_idstringsee notes—Required for service principal auth — the app registration's client id.
tenant_idstringsee notes—Required for service principal auth — the Entra tenant id.
client_secretstringsee notes—Required 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.
retriesintegerno3Connection retries. DVT honours it for its own extraction and load connections too (a connect failure is retried that many times, with the same backoff).