I Learned Something - Azure Bicep Local Extensions
Bicep Local Extensions
Azure Bicep has always been focused on the Azure Cloud. However, with an experimental feature, that is going to change.
When creating resources using Infrastructure as Code, regardless of the language, the backing call is using standard API endpoints. IaC is a wrapper around API endpoints, providing readability, structure and enhancements. Terraform already provides a way to create custom Plugins for any API endpoint, and now Bicep has introduced a feature to create Extensions.
I have watched a few demos, including Freek Berson's session at Build 2026 (In the photo of his presentation you can see the back of my hat in the audience), and I had to try it out for myself. Some examples I have seen are, using Bicep to turn on a light using Home Assist, managing Databricks, and managing GitHub Repos. My experiment is creating Work Items in Azure DevOps. This feature has a lot of potential for expanding Bicep outside of the Azure sphere.
Note: As of this blog post, Bicep Local Extensions are Experimental
Extension Overview
This extension uses the Azure DevOps .NET Client Library to create new Work Items. It can only create a Story, Bug or Product Backlog Item.
This is an example of trying out a new feature. This is not production ready code.
Required Tools
- Visual Studio Code
- Azure CLI
- Bicep CLI
- Install the Bicep CLI directly to get access to the
bicepcommands. These do not work withaz bicep
- Install the Bicep CLI directly to get access to the
- My example uses .NET 10 but in general .NET 9.0+ is aneeded
Extension Source
- Standard App entrance file
- The extensions on
builder.Servicesare different than the quickstart example from using .NET 10.
src/AzDOWorkItem.Extension.csproj
- Packages for Client Libraries
- Local Extension Package -
Azure.Bicep.Local.Extension
src/Handlers/AzDOWorkItemHandler.cs
- Handler for creating Work Items
- Code for checking that properties exist
- Instantiates AzureDevOpsClient for connecting and creating work items
- Model of the parameters to be used in the Bicep template
src/services/AzureDevOpsClient.cs
- Class with methods to interact directly with the Azure DevOps Client Library
- Create connection
- Create Work Items
Publishing Extension
Make sure to update the paths in the publish-extension command to match where dotnet publish creates the files. The path here is slightly different than the documentation.
1dotnet publish --configuration release -r osx-arm64 .
2dotnet publish --configuration release -r linux-x64 .
3dotnet publish --configuration release -r win-x64 .
4
5bicep publish-extension --bin-osx-arm64 ./bin/release/net10.0/osx-arm64/publish/bicep-ext-azdoworkitem --bin-linux-x64 ./bin/release/net10.0/linux-x64/publish/bicep-ext-azdoworkitem --bin-win-x64 ./bin/release/net10.0/win-x64/publish/bicep-ext-azdoworkitem.exe --target ./bin/bicep-ext-azdoworkitem --force
📆 Look for a future post (or update) on publishing to Azure Container Registry
Using Extension in Bicep
Files
infrastructure/bicepconfig.json
- The
experimentalFeaturesEnabledproperty is required
targetScopemust be local- The
extensionmatches the extension name set inbicep.config - VSCode intellisense will recognize and auto populate required properties like it does for standard Bicep templates
infrastructure/parameters/main.bicepparam
- Required even if no params specified
Azure and AzDO Login
Like deploying standard Bicep templates, it relies on the permissions you have in the terminal where the deploy command is executed.
There are a couple ways to authenticate to AzDO in the terminal for
Use Azure DevOps CLI Extension
1# Login to Azure
2az login
3
4# Set AzDO Default
5az devops configure --defaults organization=https://dev.azure.com/YourOrg project=YourProject
6
7az devops login --organization https://dev.azure.com/YourOrg
8# Enter PAT (Work Item - Read & Write)
Get Access token using Azure CLI
1# Login to Azure
2az login
3
4az account get-access-token --resource https://app.vssps.visualstudio.com
Deployment
A specific bicep command used to deploy the template. An important note is that it uses the .bicepparam file. So even if you have no parameters to pass in, it still needs a .bicepparam file with the using statement pointing to the main template file.
1bicep local-deploy main.bicepparam