Table of Contents
- Two Platforms, Two CI/CD Models
- ADF Git Integration Setup
- ADF CI/CD — The ARM Template Approach
- Building ADF ARM Templates with ADFUtilities
- ADF Pre and Post Deployment Scripts
- ADF Parameterization for Multi-Environment
- Complete ADF CI/CD Pipeline in YAML
- Fabric Git Integration Setup
- Fabric Deployment Pipelines — The Built-In Approach
- Deployment Rules — Environment-Specific Configuration
- Variable Libraries — Eliminating Hard-Coded References
- fabric-cicd Python Library — Programmatic Deployments
- Complete Fabric CI/CD Pipeline in YAML
- ADF vs Fabric CI/CD — Key Differences
- Common Mistakes
- Interview Questions
- Wrapping Up
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.jsonADF 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-utilitiesBuilding 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 bookmarksFabric 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 connectionsfabric-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
| Aspect | ADF CI/CD | Fabric CI/CD |
|---|---|---|
| Deployment unit | Entire factory (ARM template) | Item by item (granular) |
| Template format | ARM JSON templates | Fabric item definitions (JSON/PBIR) |
| Trigger management | Must stop/restart triggers manually | Handled automatically |
| Built-in promotion | None (pipeline-only) | Deployment Pipelines (UI + API) |
| Git integration | Dev factory only | Any workspace |
| Parameter override | ARM template parameters | Deployment rules + Variable Libraries |
| Automation library | ADFUtilities npm | fabric-cicd Python |
| Data deployment | N/A (ADF has no data) | Data NOT deployed (only definitions) |
| Partial deployment | No (all-or-nothing ARM) | Yes (select specific items) |
| Agent requirement | Windows (PowerShell for triggers) | Linux (Python for fabric-cicd) |
| Maturity | Mature (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 resolutionCommon Mistakes
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.
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.
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.
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.
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.
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.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.
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 DevOps – CI/CD for ADF with GitHub – CI/CD for Databricks – Fabric Git Integration & Deployment Pipelines – YAML Pipelines Deep Dive