Understand your templates, one step at a time.
Azure Pipelines Template Debugger is a VS Code extension that lets you set breakpoints in Azure Pipelines YAML files and step through template expansion — seeing how parameters flow, how ${{ }} expressions resolve, and which conditional branches are taken — all without executing any pipeline tasks.
- Template expansion, not task execution — we simulate Azure DevOps' compile-time template processing, not the pipeline runtime.
- Familiar debugging UX — breakpoints, call stack, variables, watch, hover, step in/out work exactly like they do for code.
- Offline by default — everything runs locally against files on disk. No Azure DevOps connection required.
🔍 Step through template expansion — walk through your pipeline YAML node by node with Step In, Step Over, and Step Out
📂 Template include stack — the Call Stack shows the full chain of template: includes and extends: references
🧮 Expression evaluation — ${{ }} compile-time expressions are evaluated in real time with 17+ built-in functions (eq, ne, contains, format, coalesce, and more)
🔀 Conditional stepping — step through ${{ if }} / ${{ elseif }} / ${{ else }} blocks and see which branch is taken
🔁 Loop iteration — ${{ each }} loops are unrolled one iteration at a time with the loop variable visible in the Variables pane
📌 Breakpoints with conditions — set conditional breakpoints like eq(parameters.environment, 'production') to stop only when it matters
👁️ Watch & hover — add watch expressions or hover over ${{ }} text to see resolved values
✏️ Inline values — resolved expression values appear as inline decorations in the editor while paused
📋 Parameters & variables scopes — inspect parameters (with defaults), variables, and template expressions for each stack frame
🔄 Restart — restart template expansion from the root pipeline without relaunching
- VS Code 1.92+
- Azure Pipelines extension (installed automatically as a dependency)
Note: This extension is currently in development and not yet published to the marketplace.
- Clone the repository
- Run
yarn installto install dependencies - Press F5 to open the Extension Development Host with the sample pipelines loaded
- Pick a launch config from the Run and Debug panel and start debugging
- Open any Azure Pipelines YAML file
- Set breakpoints by clicking the gutter
- Open the Run and Debug panel and select an
azurepipelineslaunch config - Press F5 to start debugging
| Action | Shortcut | Description |
|---|---|---|
| Step In | F11 |
Enter a template: reference or dive into a block |
| Step Over | F10 |
Execute a template reference without entering it |
| Step Out | Shift+F11 |
Return from the current template to the caller |
| Continue | F5 |
Resume to the next breakpoint |
| Restart | Ctrl+Shift+F5 |
Re-run expansion from the root pipeline |
Add to your .vscode/launch.json:
{
"type": "azurepipelines",
"request": "launch",
"name": "Debug pipeline",
"pipeline": "${workspaceFolder}/azure-pipelines.yml",
"stopOnEntry": true
}| Property | Type | Required | Description |
|---|---|---|---|
pipeline |
string |
✅ | Absolute path to the pipeline YAML file |
stopOnEntry |
boolean |
Pause on the first line (default: false) |
|
parameters |
string |
Path to a YAML file with parameter value overrides |
The extension implements the Debug Adapter Protocol in-process (no separate DAP server). The main components are:
extension.ts ← activation: registers providers
├── configurationProvider.ts ← resolves launch configs
├── debugAdapterFactory.ts ← creates DebugSession instances
├── inlineValuesProvider.ts ← inline ${{ }} value decorations
│
debugSession.ts ← DAP request/response handling
└── debugger.ts ← core execution engine
├── documentManager.ts ← YAML loading & caching
│ └── fileLoader.ts ← file I/O + YAML parsing
├── documentTraverser.ts ← AST walking, template/if/each handling
├── executionContextManager.ts ← call stack (context per template)
│ └── executionContext.ts ← pointer, params, variables, depth
├── breakpointManager.ts ← breakpoints + conditional evaluation
├── eventManager.ts ← debugger events → DAP events
└── expressionEngine/ ← ${{ }} expression evaluator
├── lexer.ts ← tokenizer
├── parser.ts ← token → AST
├── evaluator.ts ← AST → resolved value
├── functions.ts ← built-in functions (eq, ne, etc.)
└── types.ts ← Token, AST node, context types
yarn install # install dependencies
yarn run compile # build (tsc → out/)
yarn run lint # eslint
yarn run test:unit # expression engine tests (mocha, no VS Code host)
yarn run test # VS Code integration testsPress F5 in VS Code — it compiles the extension and opens a new Extension Development Host window with the sample/ folder loaded. The sample folder contains pipelines that exercise every debugger feature (parameters, template includes, conditionals, loops, extends).
| File | Demonstrates |
|---|---|
azure-pipelines.yml |
Parameters, variables, template includes, if/elseif/else, each loops |
extends-pipeline.yml |
extends: template: with [extends] call stack frames |
templates/build-steps.yml |
Step In/Out, conditionals inside templates, hover & watch |
templates/deploy-steps.yml |
Per-region deployment from each loop, conditional steps |
templates/base-pipeline.yml |
Base template for extends with nested includes |
templates/shared-variables.yml |
Variable template |
- 🔜 Remote template resolution for
resources.repositoriesreferences within the same Azure DevOps organization - 🔜 Parameter type validation against declared types (
string,number,boolean,object,stepList, etc.) - 🔜 Loaded sources tracking (see all template files involved in expansion)
Contributions are welcome! Feel free to fork the repo and submit pull requests. If you have ideas but aren't familiar with the code, you can also open issues.
See the LICENSE file for more details.