- Use four template types: stage, job, step, and variable templates — each encapsulates one reusable unit
- Store shared templates in a dedicated Git repo; reference via resources.repositories in consuming pipelines
- Use extends templates to define the pipeline skeleton — consuming pipelines fill in parameters, not structure
- Define typed parameters (string, boolean, object, stepList) with descriptions and defaults on every template
- Pin template repository references to a specific branch or tag: ref: refs/tags/v2.0 for stability
- Four template types: stage templates (deployment flows), job templates (build/test), step templates (tasks), variable templates (config)
- Dedicated template repository: store in a central repo; consuming pipelines reference via resources: repositories:
- extends templates: define the outer pipeline structure (stages, security steps, approvals); consuming pipelines fill parameters
- Step templates for reusable task sequences: checkout → cache → install → build as one template call
- Typed parameters: string, boolean, number, object, stepList — with allowed values, defaults, and descriptions
- Pin template refs: ref: refs/tags/v2.0 prevents breaking changes; use branches for development, tags for stable
- Variable templates for environment config: vars-dev.yml, vars-staging.yml, vars-prod.yml — swap per stage
- Pass steps as parameters using stepList type: allows consuming pipelines to inject custom steps into template-defined jobs
- Template expressions: ${{ if }}, ${{ each }}, ${{ parameters.x }} for compile-time logic in templates
- Limit nesting: Azure Pipelines supports 20 levels max; prefer flat composition (2-3 levels) for readability
- Document templates: add YAML comments at the top with parameter descriptions, example usage, and version history
- One template per file: don't combine stage + job + step templates — keep each file focused on one abstraction