Azure DevOps started supporting YAML pipelines in 2018. By 2019, it became the preferred way to define CI/CD, moving away from the old visual editor to pipeline definitions written in code and stored right with your application code.
With YAML pipelines, you define everything about your pipeline in code. Triggers, variables, stages, jobs, and steps all live in a .azure-pipelines.yml file within your repository. This means your pipeline definition is version-controlled alongside the code it builds. When you open a pull request that changes the pipeline itself, it automatically triggers validation, and you can see the history of pipeline changes right in your Git history. No more external configuration files to keep track of.
I've seen teams reduce their pipeline maintenance overhead by as much as 40% by switching to YAML pipelines and taking advantage of features like pipeline templates. For example, a team I worked with had 25 separate applications, each with its own build and deployment pipeline. By extracting common steps into templates, they were able to reduce the total number of lines of YAML code from over 10,000 to just 2,500. This not only made it easier to maintain but also reduced the chance of errors and inconsistencies across pipelines.
YAML also allows for multi-stage pipelines, meaning you can define your entire CI/CD workflow, from building your code all the way to deploying to production, within a single file. You can set up stages like Build, Deploy-Dev, Deploy-Staging, and Deploy-Prod to run sequentially, with defined dependencies between them. The deployment stages use Environments, which are named targets that can have approval policies and track deployment history. The build stage outputs artifacts that the deployment stages then consume, ensuring you're promoting the exact same artifact through each environment.
One of the tools that we used to manage our YAML pipelines was Azure Pipelines' built-in features like pipeline templates and variable groups, in conjunction with external tools like Azure Key Vault for secrets management. By using Azure Key Vault, we were able to securely store sensitive information like service connection names and environment URLs, and then reference them in our pipelines using variable groups. This allowed us to keep our pipeline definitions clean and secure, while still making it easy to manage and update our pipeline configurations.
To avoid repeating yourself, you can use pipeline templates. This lets you extract common sequences of steps, like standard build steps or deployment steps, into separate template files. Then, individual application pipelines can simply reference these templates and pass in environment-specific parameters. This is incredibly useful for a platform team; they can maintain consistent pipeline practices across dozens of applications without duplicating a single line of YAML.
I've also seen teams use runtime parameters to great effect, allowing users to customize pipeline runs without having to edit the pipeline definition itself. For example, a team I worked with used runtime parameters to allow developers to select which environment to deploy to, or to turn on debug mode for a specific run. This not only made it easier for developers to use the pipeline but also reduced the risk of errors and inconsistencies, since the pipeline definition itself remained unchanged.
You can manage shared configuration, like service connection names, environment URLs, or feature flags, using variable groups. Multiple pipelines can then reference these groups by name. On top of that, runtime parameters let users provide values when they trigger a pipeline. This could be selecting a deployment target, turning on debug mode for a specific run, or specifying which artifact version to deploy. These parameters are type-checked and validated before the pipeline even starts running.
In terms of specific numbers, I've seen teams achieve significant reductions in pipeline execution time by optimizing their YAML pipelines. For example, one team reduced their average pipeline execution time from 45 minutes to just 10 minutes, by optimizing their build and deployment steps, and by taking advantage of features like parallel job execution. This not only improved the overall efficiency of their CI/CD workflow but also allowed them to get feedback and results faster, which in turn improved their overall development velocity.