CI/CD for Azure Data Factory and Microsoft Fabric with Azure DevOps: ARM Templates, ADFUtilities, Trigger Management, Fabric Deployment Pipelines, Deployment Rules, Variable Libraries, fabric-cicd Library, and Complete YAML Pipeline Examples

Table of Contents

Our Azure DevOps overview covered the platform, and our YAML pipelines deep dive covered pipeline mechanics. The previous post covered Databricks CI/CD. This final DevOps post covers CI/CD for the other two major Azure data platforms: Azure Data Factory (ARM template-based) and Microsoft Fabric (deployment pipelines + Git integration).

Analogy — Two different shipping companies. ADF CI/CD is like shipping by cargo container — you pack everything into one giant ARM template container, ship it to the port (test/prod factory), and a crane (deployment task) unloads it all at once. You must stop the conveyor belts (triggers) before unloading and restart them after. Fabric CI/CD is like shipping by delivery van — you load specific items into Fabric’s built-in delivery system (deployment pipelines), which knows how to deliver each item type (Lakehouse, pipeline, notebook) with environment-specific labels (deployment rules) already attached.

Two Platforms, Two CI/CD Models

ADF CI/CD model:
  1. Connect dev ADF to Git (Azure Repos or GitHub)
  2. Develop in dev ADF (create pipelines, datasets, linked services)
  3. Publish in dev ADF → generates ARM templates in adf_publish branch
     OR use ADFUtilities npm package to build ARM templates in CI pipeline
  4. CI pipeline validates and builds ARM template artifact
  5. CD pipeline deploys ARM template to test/prod ADF with parameter overrides
  6. Pre-deployment: stop triggers. Post-deployment: restart triggers.

Fabric CI/CD model (four options):
  Option 1: Git + Deployment Pipelines (most common)
    Dev workspace linked to Git → Deployment Pipeline promotes to Test → Prod
  Option 2: Git + fabric-cicd library
    Git-backed dev → Azure DevOps pipeline uses fabric-cicd to deploy to Test/Prod
  Option 3: Deployment Pipelines only (no Git)
    Promote directly between workspaces using Fabric UI or API
  Option 4: Git + Bulk Import API
    Full programmatic control via REST APIs

Key difference:
  ADF deploys as ONE ARM template (all-or-nothing)
  Fabric deploys item by item (granular control)

ADF Git Integration Setup

Setting up Git integration for ADF:

  1. Open your DEV Azure Data Factory
  2. Manage hub → Git configuration → Configure
  3. Repository type: Azure DevOps Git
  4. Azure DevOps Organization: MyCompany
  5. Project Name: DataPlatform
  6. Repository Name: adf-pipelines
  7. Collaboration branch: main
  8. Publish branch: adf_publish (auto-created)
  9. Root folder: /src (or / for root)
  10. Import existing resources: Yes (imports current pipelines to Git)

  IMPORTANT:
  - ONLY the dev factory connects to Git
  - Test and prod factories are deployed via CI/CD only
  - Test/prod factories should NOT have Git configured
  - The adf_publish branch stores generated ARM templates (if using manual publish)
ADF Git structure in Azure Repos:

  adf-pipelines/
    └── src/
        ├── pipeline/
        |     ├── PL_Ingest_Vendor_A.json
        |     ├── PL_Ingest_Vendor_B.json
        |     └── PL_Master_Orchestrator.json
        ├── dataset/
        |     ├── DS_Source_SQL.json
        |     └── DS_Sink_ADLS.json
        ├── linkedService/
        |     ├── LS_AzureSQL_Dev.json
        |     ├── LS_ADLS_Dev.json
        |     └── LS_KeyVault_Dev.json
        ├── trigger/
        |     ├── TR_Daily_0600.json
        |     └── TR_Tumbling_Hourly.json
        ├── integrationRuntime/
        |     └── IR_SelfHosted.json
        └── factory/
              └── DataFactory_Dev.json

ADF CI/CD — The ARM Template Approach

ADF stores all its resources (pipelines, datasets, linked services, triggers) as JSON. When you deploy to another environment, you export these as an ARM template and deploy it to the target factory with parameter overrides.

Two ways to generate ARM templates:

  Method 1: Manual Publish (legacy)
    - Click "Publish" in ADF UI
    - ARM templates generated in adf_publish branch
    - CD pipeline picks up from adf_publish
    - Problem: requires manual click, can't be automated

  Method 2: ADFUtilities npm package (recommended)
    - CI pipeline builds ARM template automatically
    - No manual Publish click needed
    - Fully automated: commit → build → deploy
    - Uses @microsoft/azure-data-factory-utilities

Building ADF ARM Templates with ADFUtilities

Setup: add package.json to your ADF root folder:

  {
    "scripts": {
      "build": "node node_modules/@microsoft/azure-data-factory-utilities/lib/index"
    },
    "dependencies": {
      "@microsoft/azure-data-factory-utilities": "^1.0.0"
    }
  }
# CI pipeline step: build ARM templates from ADF JSON files
steps:
  - task: NodeTool@0
    inputs:
      versionSpec: '18.x'
    displayName: 'Install Node.js'

  - script: |
      cd src/
      npm install
      npm run build export \
        "$(Build.Repository.LocalPath)/src" \
        "/subscriptions/$(subscriptionId)/resourceGroups/$(resourceGroup)/providers/Microsoft.DataFactory/factories/$(devFactoryName)" \
        "ArmTemplate"
    displayName: 'Build ARM Template'

  - publish: src/ArmTemplate/
    artifact: adf-arm-template
    displayName: 'Publish ARM artifact'

ADF Pre and Post Deployment Scripts

Before deploying the ARM template, you must stop all triggers. After deployment, restart them. ADF provides a PowerShell script for this.

# Pre-deployment: stop triggers
- task: AzurePowerShell@5
  inputs:
    azureSubscription: 'azure-prod-connection'
    ScriptType: 'InlineScript'
    Inline: |
      $factoryName = "$(targetFactoryName)"
      $resourceGroup = "$(targetResourceGroup)"

      # Get all triggers
      $triggers = Get-AzDataFactoryV2Trigger -ResourceGroupName $resourceGroup -DataFactoryName $factoryName

      # Stop running triggers
      foreach ($trigger in $triggers) {
          if ($trigger.RuntimeState -eq "Started") {
              Stop-AzDataFactoryV2Trigger -ResourceGroupName $resourceGroup `
                  -DataFactoryName $factoryName `
                  -Name $trigger.Name -Force
              Write-Host "Stopped trigger: $($trigger.Name)"
          }
      }
    azurePowerShellVersion: 'LatestVersion'
  displayName: 'Pre-deploy: Stop triggers'

# Deploy ARM template (next section)

# Post-deployment: restart triggers
- task: AzurePowerShell@5
  inputs:
    azureSubscription: 'azure-prod-connection'
    ScriptType: 'InlineScript'
    Inline: |
      $factoryName = "$(targetFactoryName)"
      $resourceGroup = "$(targetResourceGroup)"

      # Get all triggers
      $triggers = Get-AzDataFactoryV2Trigger -ResourceGroupName $resourceGroup -DataFactoryName $factoryName

      # Start triggers
      foreach ($trigger in $triggers) {
          Start-AzDataFactoryV2Trigger -ResourceGroupName $resourceGroup `
              -DataFactoryName $factoryName `
              -Name $trigger.Name -Force
          Write-Host "Started trigger: $($trigger.Name)"
      }
    azurePowerShellVersion: 'LatestVersion'
  displayName: 'Post-deploy: Start triggers'

ADF Parameterization for Multi-Environment

ADF uses ARM template parameters to swap environment-specific values (linked service connection strings, Key Vault URLs, storage account names) during deployment.

What gets parameterized:

  Linked Services:
    - Connection strings (different servers per environment)
    - Key Vault URLs (dev Key Vault vs prod Key Vault)
    - Storage account URLs (dev storage vs prod storage)

  Pipelines:
    - Default parameter values
    - Integration Runtime references

  Triggers:
    - Schedule times (different schedules per environment)

  Example ARM template parameter overrides:
    Dev:  LS_AzureSQL.connectionString = "Server=sql-dev.database.windows.net..."
    Prod: LS_AzureSQL.connectionString = "Server=sql-prod.database.windows.net..."
# Deploy ARM template with parameter overrides
- task: AzureResourceManagerTemplateDeployment@3
  inputs:
    deploymentScope: 'Resource Group'
    azureResourceManagerConnection: 'azure-prod-connection'
    subscriptionId: '$(prodSubscriptionId)'
    resourceGroupName: '$(prodResourceGroup)'
    location: 'Canada Central'
    templateLocation: 'Pipeline Artifact'
    csmFile: '$(Pipeline.Workspace)/adf-arm-template/ARMTemplateForFactory.json'
    csmParametersFile: '$(Pipeline.Workspace)/adf-arm-template/ARMTemplateParametersForFactory.json'
    overrideParameters: |
      -factoryName "$(prodFactoryName)"
      -LS_AzureSQL_connectionString "$(PROD_SQL_CONNECTION)"
      -LS_KeyVault_properties_typeProperties_baseUrl "$(PROD_KV_URL)"
      -LS_ADLS_properties_typeProperties_url "$(PROD_STORAGE_URL)"
  displayName: 'Deploy ARM Template to Prod'

Complete ADF CI/CD Pipeline in YAML

# pipelines/adf-cicd.yml
trigger:
  branches:
    include: [main]
  paths:
    include: [src/**]

variables:
  - group: 'adf-dev-config'
  - name: devFactoryName
    value: 'adf-dataplatform-dev'

stages:
  # Stage 1: Build ARM Template
  - stage: Build
    displayName: 'Build ARM Template'
    pool:
      vmImage: 'ubuntu-latest'
    jobs:
      - job: BuildARM
        steps:
          - task: NodeTool@0
            inputs:
              versionSpec: '18.x'
          - script: |
              cd src/
              npm install
              npm run build export \
                "$(Build.Repository.LocalPath)/src" \
                "/subscriptions/$(devSubscriptionId)/resourceGroups/$(devResourceGroup)/providers/Microsoft.DataFactory/factories/$(devFactoryName)" \
                "ArmTemplate"
            displayName: 'Generate ARM Template'
          - publish: src/ArmTemplate/
            artifact: adf-arm-template

  # Stage 2: Deploy to Prod
  - stage: DeployProd
    displayName: 'Deploy to Production'
    dependsOn: Build
    pool:
      vmImage: 'windows-latest'    # PowerShell tasks need Windows
    variables:
      - group: 'adf-prod-config'
    jobs:
      - deployment: DeployADF
        environment: 'production'
        strategy:
          runOnce:
            deploy:
              steps:
                - download: current
                  artifact: adf-arm-template

                # Stop triggers
                - task: AzurePowerShell@5
                  inputs:
                    azureSubscription: 'azure-prod-connection'
                    ScriptType: 'InlineScript'
                    Inline: |
                      $triggers = Get-AzDataFactoryV2Trigger -ResourceGroupName "$(prodResourceGroup)" -DataFactoryName "$(prodFactoryName)"
                      $triggers | Where-Object { $_.RuntimeState -eq "Started" } | ForEach-Object {
                        Stop-AzDataFactoryV2Trigger -ResourceGroupName "$(prodResourceGroup)" -DataFactoryName "$(prodFactoryName)" -Name $_.Name -Force
                      }
                    azurePowerShellVersion: 'LatestVersion'
                  displayName: 'Stop triggers'

                # Deploy ARM template
                - task: AzureResourceManagerTemplateDeployment@3
                  inputs:
                    azureResourceManagerConnection: 'azure-prod-connection'
                    subscriptionId: '$(prodSubscriptionId)'
                    resourceGroupName: '$(prodResourceGroup)'
                    location: 'Canada Central'
                    csmFile: '$(Pipeline.Workspace)/adf-arm-template/ARMTemplateForFactory.json'
                    csmParametersFile: '$(Pipeline.Workspace)/adf-arm-template/ARMTemplateParametersForFactory.json'
                    overrideParameters: '-factoryName "$(prodFactoryName)" -LS_KeyVault_properties_typeProperties_baseUrl "$(PROD_KV_URL)"'
                  displayName: 'Deploy ARM Template'

                # Restart triggers
                - task: AzurePowerShell@5
                  inputs:
                    azureSubscription: 'azure-prod-connection'
                    ScriptType: 'InlineScript'
                    Inline: |
                      $triggers = Get-AzDataFactoryV2Trigger -ResourceGroupName "$(prodResourceGroup)" -DataFactoryName "$(prodFactoryName)"
                      $triggers | ForEach-Object {
                        Start-AzDataFactoryV2Trigger -ResourceGroupName "$(prodResourceGroup)" -DataFactoryName "$(prodFactoryName)" -Name $_.Name -Force
                      }
                    azurePowerShellVersion: 'LatestVersion'
                  displayName: 'Start triggers'

Fabric Git Integration Setup

Connecting a Fabric workspace to Azure DevOps Git:

  1. Open Fabric workspace (must have Admin or Member role)
  2. Workspace Settings → Git integration
  3. Connect:
     - Git provider: Azure DevOps
     - Organization: MyCompany
     - Project: DataPlatform
     - Repository: fabric-content
     - Branch: main (or develop for dev workspace)
     - Git folder: /FabricContent (or /)
  4. Sync direction: choose "Commit workspace to Git" (first time)

  What gets synced to Git:
    Lakehouses (definition only, not data)
    Notebooks
    Pipelines (Data Factory)
    Reports and Semantic Models
    Warehouses (definition only)
    Spark Job Definitions
    Environments

  What does NOT sync:
    Actual data in Lakehouses/Warehouses
    Query results
    Scheduled refresh configurations
    Personal bookmarks

Fabric Deployment Pipelines — The Built-In Approach

Fabric Deployment Pipelines provide a built-in promotion mechanism: Dev → Test → Prod. You assign a workspace to each stage and promote items between them.

Setting up Fabric Deployment Pipelines:

  1. Open Fabric portal → Deployment Pipelines (left nav)
  2. Create Pipeline → name: "DataPlatform-Pipeline"
  3. Add stages:
     - Development → assign "DataPlatform-Dev" workspace
     - Test → assign "DataPlatform-Test" workspace
     - Production → assign "DataPlatform-Prod" workspace
  4. Deploy: click the arrow between stages to promote items

  What happens during deployment:
    - Item definitions are copied to the target workspace
    - Deployment rules apply environment-specific values
    - Data is NOT copied (Lakehouses and Warehouses keep their own data)
    - Each workspace has its own compute, connections, and data

  Deployment options:
    - Deploy all items (everything in the workspace)
    - Deploy selected items (choose specific notebooks, pipelines)
    - Deploy only changed items (since last deployment)

Deployment Rules — Environment-Specific Configuration

Deployment rules automatically swap environment-specific values when promoting between stages.

Types of deployment rules:

  Data source rules:
    - Change the data source connection (dev SQL → prod SQL)
    - Change the Lakehouse (dev Lakehouse → prod Lakehouse)
    - Change the storage account

  Parameter rules:
    - Override pipeline parameter default values
    - Override notebook parameter values

  Connection rules:
    - Swap connections between environments

Setting up deployment rules:
  1. Deployment Pipelines → select your pipeline
  2. Click the gear icon on the target stage (Test or Production)
  3. Select an item → Add Rule
  4. Choose rule type (data source, parameter, connection)
  5. Set the target value for that stage

Example:
  Dev:  Notebook connects to Lakehouse "LH_Dev"
  Test: Deployment rule changes to Lakehouse "LH_Test"
  Prod: Deployment rule changes to Lakehouse "LH_Prod"

Variable Libraries — Eliminating Hard-Coded References

Variable Libraries (announced FabCon 2026) eliminate hard-coded Lakehouse IDs, connection strings, and parameters in Fabric items. They resolve automatically per workspace.

How Variable Libraries work:

  Instead of:
    Notebook code: lakehouse_id = "abc-123-def-456"  # Hard-coded dev Lakehouse

  With Variable Libraries:
    Notebook code: lakehouse_id = variable_library.get("lakehouse_id")
    Dev workspace:  variable_library["lakehouse_id"] = "abc-123-dev"
    Prod workspace: variable_library["lakehouse_id"] = "xyz-789-prod"

  Benefits:
    - No deployment rules needed for parameterized values
    - Code is identical across environments
    - Variables resolve at runtime based on workspace
    - Works with Git integration and deployment pipelines
    - Connection reference variables for database connections

fabric-cicd Python Library — Programmatic Deployments

The fabric-cicd library enables deploying Fabric items from an Azure DevOps pipeline, giving you the same CI/CD control as ADF ARM templates but for Fabric.

# Deploy Fabric items using fabric-cicd in Azure DevOps
steps:
  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.11'

  - script: |
      pip install fabric-cicd
    displayName: 'Install fabric-cicd'

  - script: |
      python -c "
      from fabric_cicd import FabricWorkspace, publish_all_items

      # Connect to target workspace
      ws = FabricWorkspace(
          workspace_id='$(TARGET_WORKSPACE_ID)',
          repository_directory='$(Build.Repository.LocalPath)/FabricContent',
          item_type_in_scope=['Notebook', 'DataPipeline', 'SemanticModel', 'Report']
      )

      # Deploy all items in scope
      publish_all_items(ws)
      print('Deployment complete')
      "
    displayName: 'Deploy to Fabric workspace'
    env:
      AZURE_CLIENT_ID: $(ARM_CLIENT_ID)
      AZURE_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
      AZURE_TENANT_ID: $(ARM_TENANT_ID)

Complete Fabric CI/CD Pipeline in YAML

# pipelines/fabric-cicd.yml
trigger:
  branches:
    include: [main]
  paths:
    include: [FabricContent/**]

stages:
  # Stage 1: Validate
  - stage: Validate
    displayName: 'Validate Fabric Items'
    pool:
      vmImage: 'ubuntu-latest'
    jobs:
      - job: Validate
        steps:
          - script: |
              pip install fabric-cicd ruff
              # Lint notebooks
              find FabricContent/ -name "*.py" | xargs ruff check --output-format=github
            displayName: 'Lint and validate'

  # Stage 2: Deploy to Test
  - stage: DeployTest
    displayName: 'Deploy to Test'
    dependsOn: Validate
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      - group: 'fabric-test-credentials'
    jobs:
      - deployment: DeployFabricTest
        environment: 'staging'
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
                - script: |
                    pip install fabric-cicd
                    python deploy_fabric.py --workspace-id $(TEST_WORKSPACE_ID)
                  displayName: 'Deploy to Test workspace'
                  env:
                    AZURE_CLIENT_ID: $(ARM_CLIENT_ID)
                    AZURE_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
                    AZURE_TENANT_ID: $(ARM_TENANT_ID)

  # Stage 3: Deploy to Prod
  - stage: DeployProd
    displayName: 'Deploy to Production'
    dependsOn: DeployTest
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      - group: 'fabric-prod-credentials'
    jobs:
      - deployment: DeployFabricProd
        environment: 'production'
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
                - script: |
                    pip install fabric-cicd
                    python deploy_fabric.py --workspace-id $(PROD_WORKSPACE_ID)
                  displayName: 'Deploy to Production workspace'
                  env:
                    AZURE_CLIENT_ID: $(ARM_CLIENT_ID)
                    AZURE_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
                    AZURE_TENANT_ID: $(ARM_TENANT_ID)

ADF vs Fabric CI/CD — Key Differences

AspectADF CI/CDFabric CI/CD
Deployment unitEntire factory (ARM template)Item by item (granular)
Template formatARM JSON templatesFabric item definitions (JSON/PBIR)
Trigger managementMust stop/restart triggers manuallyHandled automatically
Built-in promotionNone (pipeline-only)Deployment Pipelines (UI + API)
Git integrationDev factory onlyAny workspace
Parameter overrideARM template parametersDeployment rules + Variable Libraries
Automation libraryADFUtilities npmfabric-cicd Python
Data deploymentN/A (ADF has no data)Data NOT deployed (only definitions)
Partial deploymentNo (all-or-nothing ARM)Yes (select specific items)
Agent requirementWindows (PowerShell for triggers)Linux (Python for fabric-cicd)
MaturityMature (5+ years)Growing (new features at FabCon 2026)

Choosing the right approach:

  ADF pipelines:
    → Use ARM template approach with ADFUtilities
    → Stop/start triggers in pre/post deployment
    → Override linked service parameters per environment

  Fabric items:
    → Use Git + deployment pipelines (simplest)
    → OR Git + fabric-cicd library (most control)
    → Set deployment rules for environment-specific config
    → Use Variable Libraries for runtime resolution

Common Mistakes

  1. Configuring Git on test and prod ADF factories. Only the dev factory should have Git integration. Test and prod factories receive updates exclusively through CI/CD ARM template deployments. Git integration on test/prod causes merge conflicts and deployment issues.

  2. Forgetting to stop triggers before ADF deployment. Deploying an ARM template while triggers are running causes conflicts and can trigger unintended pipeline runs. Always stop triggers before deployment and restart them after. Use the PowerShell pre/post deployment scripts.

  3. Using the manual Publish button instead of ADFUtilities. The Publish button requires a human to click it, breaking automation. ADFUtilities generates ARM templates automatically in the CI pipeline, enabling fully automated deployments triggered by code merges.

  4. Not parameterizing linked services for ADF. If linked service connection strings are hardcoded in the ARM template, deploying to prod connects to dev databases. Parameterize every environment-specific value: connection strings, Key Vault URLs, storage account URLs, and schedule times.

  5. Deploying all Fabric items when only one changed. Fabric deployment pipelines support selective deployment. Deploying everything when only one notebook changed wastes time and risks overwriting items that were modified directly in the target workspace. Deploy only changed items.

  6. Hard-coding Lakehouse IDs in Fabric notebooks. A notebook with lakehouse_id = "abc-123-dev" breaks when deployed to test or prod. Use Variable Libraries (FabCon 2026) or deployment rules to swap Lakehouse references per environment. Keep notebook code environment-agnostic.

  7. Not using service principals for Fabric CI/CD. Using personal accounts for deployment means pipelines break when the user changes their password or leaves the company. Create a service principal with workspace Admin or Member role for CI/CD deployments.

  8. Assuming Fabric deployment pipelines copy data. Deployment pipelines promote item definitions (notebooks, pipeline JSON, semantic model schemas), NOT the data in Lakehouses or Warehouses. Each environment maintains its own data independently. After deploying a new Lakehouse definition to prod, you still need to run the data pipeline to populate it.

Interview Questions

Q: How does ADF CI/CD work with Azure DevOps? A: Only the dev factory connects to Git (Azure Repos). Developers create and modify pipelines in the dev factory, which syncs changes to Git automatically. The CI pipeline uses the ADFUtilities npm package to validate ADF resources and generate ARM templates as build artifacts. The CD pipeline deploys the ARM template to test and prod factories using the AzureResourceManagerTemplateDeployment task with parameter overrides for environment-specific values like connection strings and Key Vault URLs. Pre-deployment stops triggers and post-deployment restarts them.

Q: What is the difference between using adf_publish and ADFUtilities? A: The adf_publish branch is populated when someone manually clicks Publish in the ADF UI — this requires human intervention and breaks automation. ADFUtilities is an npm package that generates ARM templates automatically in a CI pipeline, triggered by code merges. ADFUtilities enables fully automated CI/CD without manual clicks. For new projects, always use ADFUtilities.

Q: How do Fabric deployment pipelines work? A: Fabric deployment pipelines provide built-in promotion between workspaces (Dev → Test → Prod). You assign a workspace to each stage and click deploy to promote items. Deployment copies item definitions (notebooks, pipelines, semantic models) but not data. Deployment rules automatically swap environment-specific values (Lakehouse references, connections, parameters). Promotion can be triggered from the Fabric UI, the deployment pipelines API, or programmatically from Azure DevOps using the fabric-cicd Python library.

Q: What are Variable Libraries and how do they improve Fabric CI/CD? A: Variable Libraries (announced FabCon 2026) eliminate hard-coded references in Fabric items. Instead of embedding Lakehouse IDs or connection strings directly in notebooks, you reference variables that resolve automatically per workspace. When an item is promoted via deployment pipelines or Git, the Variable Library ensures the correct configuration is applied with no manual reconfiguration. This replaces the need for deployment rules for parameterized values and keeps notebook code identical across environments.

Q: What are the key differences between ADF and Fabric CI/CD? A: ADF deploys the entire factory as one ARM template (all-or-nothing), requires manual trigger stop/start, and uses ARM parameter overrides for environment configuration. Fabric deploys item by item (granular), handles triggers automatically, and uses deployment rules or Variable Libraries for environment-specific values. ADF CI/CD is more mature (5+ years of tooling). Fabric CI/CD is newer but more flexible, with built-in deployment pipelines and the fabric-cicd Python library for programmatic control.

Q: Why must you stop triggers before deploying ADF ARM templates? A: ARM template deployment updates the ADF resource in Azure, including trigger definitions. If a trigger is running during deployment, the update conflicts with the running state, potentially causing deployment failures or triggering unintended pipeline runs with mixed old and new configurations. Stopping triggers ensures a clean deployment. The pre-deployment PowerShell script stops all active triggers, the ARM template deploys cleanly, and the post-deployment script restarts them.

Q: How would you set up Fabric CI/CD with Azure DevOps for an enterprise team? A: Connect the dev workspace to an Azure DevOps Git repository. Developers work in the dev workspace and commit changes to Git. The CI pipeline validates and lints items on every PR. For deployment, use either Fabric deployment pipelines (simplest — promotion between workspaces with deployment rules) or the fabric-cicd Python library in an Azure DevOps YAML pipeline (most control — programmatic deployment with approval gates). Create separate workspaces per environment (Dev, Test, Prod), each with its own capacity. Use service principals for authentication. Use Variable Libraries to eliminate hard-coded references across environments.

Wrapping Up

ADF and Fabric have fundamentally different CI/CD models. ADF uses ARM templates — export everything from dev, deploy as one package to test and prod with parameter overrides and trigger management. Fabric uses deployment pipelines and Git integration — promote individual items between workspaces with deployment rules and Variable Libraries for environment-specific configuration.

Both work with Azure DevOps YAML pipelines. Both support approval gates, variable groups, and service principal authentication. The choice is dictated by the platform you use, not by preference. And for teams using both ADF and Fabric, you will likely maintain separate CI/CD pipelines for each — they are different enough that combining them adds complexity without benefit.

This post completes the DevOps series. You now have the full stack: Azure DevOps platform, YAML pipelines, Terraform infrastructure, Databricks DABs deployment, ADF ARM templates, and Fabric deployment pipelines — all automated through Git, tested through CI, and promoted through CD with approval gates.

Related posts:CI/CD for ADF with Azure DevOpsCI/CD for ADF with GitHubCI/CD for DatabricksFabric Git Integration & Deployment PipelinesYAML Pipelines Deep Dive

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top