The full answer
Connect only the dev factory to Git, build changes in feature branches with pull requests, publish from the collaboration branch, and let an Azure Pipelines release deploy the generated ARM template to test and then production with per-environment parameters. Keep connection details in a Key Vault per environment with the same secret names, so only the vault URL changes. Wrap the deployment in the pre- and post-deployment script that stops triggers first and starts them after.
1. The flow
- Developers work in feature branches in the dev factory and test with debug runs.
- A pull request into
main(the collaboration branch) gets a review. - Publishing from
mainwrites the ARM template (ARMTemplateForFactory.jsonand its parameters) to the publish branch, or a build creates it with the ADF npm package. - The release deploys that template to test, runs checks, then to production after approval.
Test and production factories have no Git connection. Nobody edits them in the portal; a change made there is overwritten by the next release.
2. Why production pointed at dev storage
The linked service's URL was not a template parameter, or the import used dev's parameter values. Fix it twice over:
- Key Vault per environment, same secret names (
lake-url,sql-conn) in each. The linked services read secrets, and the only parameter left is the vault's base URL. Production secrets stay out of developers' reach. arm-template-parameters-definition.jsonin the repository root makes the properties you need into parameters (for example the vault URL, a storageurl, a Databricks workspace URL). Each environment has its own parameter file in the release.
A template has a limit of 256 parameters, so a large factory should parameterize what really differs, not everything.
3. Why the trigger fired mid-deployment
Deploying while triggers are live lets one start a pipeline whose datasets and linked services are half updated. Microsoft recommends stopping triggers before the deployment and starting them after:
- task: AzurePowerShell@5
displayName: Stop ADF triggers
inputs:
scriptPath: PrePostDeploymentScript.Ver2.ps1 # Ver2 stops only the triggers that changed
ScriptArguments: -armTemplate "$(armTemplate)" -ResourceGroupName rg-data-prd -DataFactoryName adf-data-prd -predeployment $true -deleteDeployment $false
azurePowerShellVersion: LatestVersion
pwsh: true
# ... ARM template deployment with the production parameter file ...
- task: AzurePowerShell@5
displayName: Start ADF triggers and remove deleted resources
inputs:
scriptPath: PrePostDeploymentScript.Ver2.ps1
ScriptArguments: -armTemplate "$(armTemplate)" -ResourceGroupName rg-data-prd -DataFactoryName adf-data-prd -predeployment $false -deleteDeployment $true
azurePowerShellVersion: LatestVersion
pwsh: true
The post-deployment step also deletes pipelines and datasets removed in dev, which a plain ARM deployment would leave behind.
4. Details that break releases
- Integration runtimes need the same names and types in every factory. A self-hosted runtime can be shared from one factory and linked into the others.
- No selective publishing: publishing includes all merged changes. To release only part, keep unfinished work behind a feature flag (a global parameter and an If Condition), or use a hotfix branch for urgent fixes.
- Use
_or-instead of spaces in resource names.
What interviewers want: Git on dev only, ARM templates promoted by a release, parameters through a custom definition file and per-environment Key Vaults, stopping and starting triggers around the deployment, cleanup of deleted resources, and feature flags instead of selective publishing.
Last updated 16 October 2026