Introduction to Bicep Local Deploy extensions
Bicep Local Deploy extensions launched their simplified authoring experience in v0.37.4, opening up a whole new world of management capabilities outside Azure. They're .NET-based services that enable Bicep to manage any resource with a REST API. From third-party SaaS platforms to internal APIs and custom services, you can now create an extension and write a Bicep file to deploy your infrastructure — just like you would with native Azure resources.
Unlike traditional Bicep, which is limited to Azure Resource Manager, Bicep Local Deploy extensions let you bring your own resources into your deployment. You define:
- The type models with .NET.
- The handlers that communicate with REST APIs.
- Bicep starts treating these custom resources like native Azure resources.
What you'll learn:
In this module, you'll learn the fundamentals of working with Bicep Local Deploy extensions. By the end of this module, you'll be able to:
- Understand what Bicep Local Deploy extensions are and how they extend Bicep's capabilities.
- Identify the key components of the framework and their roles.
- Recognize real-world scenarios where custom extensions add value.
- Set up your development environment with .NET SDK and other tooling.
- Scaffold a new extension project using templates.
What are Bicep Local Deploy extensions?
Bicep Local Deploy extensions enable you to extend Bicep's capabilities outside Azure. Normally, you would use the Azure CLI or PowerShell to deploy a Bicep file. But what if you're not working with Azure and still want to use Bicep's framework?
That's where Bicep Local Deploy extensions come in. You can manage custom resources through REST APIs, integrate with your third-party services, and create Infrastructure as Code (IaC) solutions for any platform that exposes an HTTP API.
How extensions work
Extensions are tiny .NET applications that run locally during Bicep deployments. When Bicep encounters a resource type defined by your extension, it communicates with your extension service to:
- Preview the resource state before deployment.
- Create or update resources based on your Bicep configuration.
- Retrieve resource identifiers and output properties.
Here's a rough diagram of how the components interact:

This architecture allows Bicep to maintain its declarative syntax while enabling integration with any REST API.
Key components
The Bicep Local Deploy ecosystems consist of several key components, where one is developed by the Bicep team and the other by the community.
The Azure.Bicep.Local.Extension library
The official .NET library from the Bicep team for building local extensions:
TypedResourceHandler<TProps, TIdentifiers, TConfig>– Base class for resource handlers.ResourceRequestandResourceResponse– Request/response handling.- Extension host configuration and registration.
- HTTP client integration for REST APIs.
Here's a C# snippet of how a basic resource handler structure looks:
using Bicep.Local.Extension.Types;
public class ApiKeyHandler : TypedResourceHandler<ApiKeyProperties, ApiKeyIdentifiers, ApiKeyConfig>
{
public ApiKeyHandler(HttpClient httpClient) : base(httpClient)
{
}
// Preview what will be created/updated
public override Task<ResourceResponse<ApiKeyProperties>> Preview(
ResourceRequest<ApiKeyProperties, ApiKeyConfig> request)
{
// Preview logic here
}
// Create or update the resource
public override Task<ResourceResponse<ApiKeyProperties>> CreateOrUpdate(
ResourceRequest<ApiKeyProperties, ApiKeyConfig> request)
{
// Call REST API to create/update
}
// Delete the resource
public override Task<ResourceResponse<ApiKeyProperties>> Delete(
ResourceRequest<ApiKeyProperties, ApiKeyConfig> request)
{
// Call REST API to delete
}
// Get resource identifiers
public override Task<ResourceResponse<ApiKeyIdentifiers>> GetIdentifiers(
ResourceRequest<ApiKeyProperties, ApiKeyConfig> request)
{
// Return unique identifiers
}
}The Bicep.Local.Extension.Types.Attributes
These are the core attributes provided by the Bicep team for defining resource types and their properties. The attributes are fundamental to creating Bicep resources, providing type safety and metadata that enables the IntelliSense in your editor.
Every extension must use these attributes to define its resource schema:
[ResourceType]– Marks a class as a Bicep resource type with a unique identifier.[TypeProperty]– Defines resource properties with descriptions, required/optional flags, and read-only outputs.
The following example defines a resource type with its core attributes:
using Bicep.Local.Extension.Types.Attributes;
// Mark this class as a Bicep resource type
[ResourceType("ApiKey")]
public class ApiKeyProperties
{
// Required property
[TypeProperty(Description = "The name of the API key", Required = true)]
public string? Name { get; set; }
// Optional property with validation
[TypeProperty(Description = "The environment where the key is used")]
public string? Environment { get; set; }
// Read-only output property
[TypeProperty(Description = "The generated API key value", ReadOnly = true)]
public string? KeyValue { get; set; }
// Secure property (hidden in logs)
[TypeProperty(Description = "Metadata for the key", Secure = true)]
public string? Metadata { get; set; }
}
// Identifiers class for unique resource identification
public class ApiKeyIdentifiers
{
[TypeProperty(Description = "The unique identifier of the API key")]
public string? Id { get; set; }
[TypeProperty(Description = "The resource name")]
public string? Name { get; set; }
}
// Configuration class for extension settings
public class ApiKeyConfig
{
[TypeProperty(Description = "The base URL of the API")]
public string? BaseUrl { get; set; }
[TypeProperty(Description = "Authentication token", Secure = true)]
public string? Token { get; set; }
}The Bicep.LocalDeploy library (optional)
The unofficial library created by the community to provide attributes to annotate your resource models for documentation generation. It consists of four annotation attributes you can add to your code:
[BicepDocHeading]– Customizes documentation headings.[BicepDocExample]– Adds usage examples to documentation.[BicepFrontMatter]– Adds YAML front matter for documentation sites.[BicepDocCustom]– Includes custom documentation sections.
The following example illustrates how you can add these annotation attributes:
using Bicep.LocalDeploy;
using Bicep.Local.Extension.Types.Attributes;
[BicepFrontMatter("title: ApiKey Resource\nlayout: documentation")]
[BicepDocHeading("API Key Management", "Manage API keys for your service")]
[ResourceType("ApiKey")]
public class ApiKeyProperties
{
[TypeProperty(Description = "The name of the API key", Required = true)]
[BicepDocExample("myApiKey", "A unique identifier for your API key")]
public string? Name { get; set; }
[TypeProperty(Description = "The environment where the key is used")]
[BicepDocExample("production", "Valid values: development, staging, production")]
public string? Environment { get; set; }
[TypeProperty(Description = "Expiration date in ISO 8601 format")]
[BicepDocExample("2025-12-31T23:59:59Z", "When the API key expires")]
public string? ExpiresAt { get; set; }
[TypeProperty(Description = "The generated API key value", ReadOnly = true)]
[BicepDocCustom("Security", "This value is sensitive and should be stored securely")]
public string? KeyValue { get; set; }
}Bicep Local docs generator CLI (optional)
A command-line tool developed by the community that generates Markdown documentation from the earlier-mentioned annotated models. When you use the Bicep.LocalDeploy library annotations to decorate your resource models, the bicep-local-docgen transforms them into rich documentation with:
- Examples
- Usage patterns
- Property descriptions
- Custom sections
Key capabilities of the CLI:
- Analyzes C# source code using Roslyn compiler services.
- Extracts documentation from both core Bicep attributes and documentation specific.
- Generates consistent Markdown documentation with proper formatting.
- Validates documentation completeness by running analysis.
Example usage can be found on GitHub.
Bicep Local Deploy templates
The Bicep Local Deploy templates are unofficial and created by the community. It are .NET templates to accelerate extension development by providing a complete working starting point. These templates embody best practices and include a build automation script that builds and publishes your extension locally.
What the templates provide:
- Preconfigured project structure with organized folders for:
- Models
- Handlers
- Configuration
- Sample resource models annotated with both core Bicep and documentation attributes.
- Build and publish scripts (PowerShell) for packing your extension.
- README with setup instructions and development guidelines.
Throughout this course, you'll use this to scaffold your extension project.
Real-world scenarios
Where do Bicep Local Deploy extensions shine? Well, you've already read it in this lesson: "when you want to manage resources outside Azure and leverage Bicep."
Many organizations use a hybrid approach by combining Azure infrastructure with third-party SaaS platforms, on-premises systems, or custom internal APIs. Often, they extend Bicep with custom deployment scripts to entirely write in Bicep. This leads to the development of large deployment scripts. Extensions bridge this gap. Rather than working with multiple tools and deployment scripts, you develop an extension.
The following subsections describe some common scenarios in which extensions add value.
Scenario 1: Managing Databricks resources
You've developed your IaC in Bicep to deploy an Azure Databricks instance and any other required resources. You now want to create a resource within the instance, but you hit a wall: it's not possible to use Bicep out of the box.
That's where an extension comes into play. Databricks always offered a rich REST API, and as you've just learned, extensions can leverage REST APIs to extend further. Here's an example in Bicep code to create a Databricks cluster:
resource cluster 'Cluster' = {
name: 'analytics-cluster'
sparkVersion: '13.3.x-scala2.12'
nodeTypeId: 'Standard_DS3_v2'
numWorkers: 2
}Scenario 2: Configuring SaaS applications
Your team is deploying applications to Azure, but you also need to set up GitHub repositories, maybe configure CI/CD secrets, and add collaborators. Typically, you'd use the GitHub CLI or manually configure it. This fragments your deployment across multiple tools and scripts.
With a GitHub extension, you can manage your entire pipeline in a single Bicep template. GitHub provides REST API calls for multiple areas, and extensions bring that directly into your IaC workflow. Here's an example in Bicep code to create a GitHub repository with secrets and collaborators:
extension github with {
token: githubToken
}
resource repo 'Repository' = {
owner: owner
name: 'my-app'
description: 'Application repository'
visibility: 'Public'
}
resource collaborator 'Collaborator' = {
owner: owner
repo: repo.name
user: collaboratorName
}
resource secret 'ActionsSecret' = {
owner: owner
repo: repo.name
name: 'AZURE_CREDENTIALS'
value: azureServicePrincipalSecret
}targetScope = 'local' and targetScope = 'subscription'.Scenario 3: Custom resource providers
Many organizations build internal APIs for managing resources that are unique to their business needs. These systems often lack IaC tooling, forcing teams to rely on custom scripts or even do it manually.
With Bicep extensions, you can bring your internal APIs into the Bicep IaC ecosystem. By creating an extension for your custom resource provider, platform teams can expose a consistent, type-safe interface for managing these internal resources.
This approach is valuable for building internal developer platforms where standardization and self-service are key priorities. Here's an example of how that would look like roughly:
extension inventory with {
baseUrl: 'https://inventory.myorganization.com/api'
}
resource server 'Inventory' = {
hostname: 'app-server-01'
environment: 'production'
team: 'platform-engineering'
}Architecture overview
Understanding the architecture helps you effective Bicep Local Deploy extensions. Unlike traditional Bicep deployments that communicate directly with Azure Resource Manager, the Bicep Local Deploy extension introduces a local service layer that acts as a bridge between Bicep's declarative syntax and any REST API.
This architectural pattern gives you the flexibility to integrate with any HTTP-enabled service while maintaining Bicep's type safety, validation, and declarative deployment model.
The architecture is designed for extensibility and isolation. Each extension runs a separate .NET application, allowing you to version, test, and deploy extensions independently. The Bicep CLI discovers and communicates with extensions through JSON-RPC, sending requests and receiving responses. Your extension translates these requests into REST API calls and returns the output.
┌─────────────────┐
│ Bicep file │
│ (main.bicep) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Bicep CLI │◄─────── Bicep compilation
└────────┬────────┘
│
▼
┌─────────────────┐
│ Extension │
│ Service │
└────────┬────────┘
│
▼
┌─────────────────┐
│ REST API │
│ (Your service) │
└─────────────────┘Component interaction flow
The lifecycle of an extension deployment follows a predictable pattern, mirroring the declarative nature of Bicep itself:
- Design time: You write Bicep files using extension resources with full IntelliSense support. The Bicep language service validates your syntax, checks the property types, and provides suggestions based on your extension's type definitions.
- Build time: Bicep CLI validates syntax and types, ensuring all required properties are present and correctly typed.
- Deploy time: Extension service receives request from the Bicep CLI (
bicep local-deploy) for each resource operation. The extension validates incoming requests and determines what actions need to be taken against the target API. - Runtime: The extension makes the actual REST API calls to manage resources, handle authentication, and parse responses.
- Completion: Extension returns resource outputs to Bicep.
Setting up your development environment
Setting up your development environment for Bicep Local Deploy extensions is straightforward. It works across Windows, macOS, and Linux. The cross-platform nature of .NET means you can develop extensions on your preferred operating system.
In this section, you'll install the core dependencies needed to build extensions:
- The .NET SDK
- The Bicep CLI
- Project templates
- Documentation generator
The installation process can be automated through package managers, making it easy for you to get started. Once everything is installed, you'll verify your setup by creating a test extension project.
Install .NET SDK
The .NET SDK is available for all major platforms. Choose the installation method for your operating system.
For Windows:
# Install .NET 9.0 SDK using WinGet
winget install Microsoft.DotNet.SDK.9
# Verify installation
dotnet --version
# Should output: 9.0.x or laterFor macOS:
# Install .NET SDK using Homebrew
brew install dotnet-sdk
# Verify installation
dotnet --versionFor Linux (Ubuntu/Debian):
# Add Microsoft package repository
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
# Install .NET SDK
sudo apt-get update
sudo apt-get install -y dotnet-sdk-9.0
# Verify installation
dotnet --versionFor other Linux distributions or manual installation, visit the official .NET download page.
Installing Bicep CLI
The Bicep CLI is required to compile and deploy Bicep Local Deploy files. Install it using your platform's package manager.
For Windows:
# Install Bicep CLI using WinGet
winget install Microsoft.Bicep
# Verify installation
bicep --versionFor macOS:
# Install Bicep CLI using Homebrew
brew install bicep
# Verify installation
bicep --versionFor Linux (using Azure CLI):
# Install Azure CLI first if not already installed
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Install Bicep CLI via Azure CLI
az bicep install
# Verify installation
bicep --versionAlternatively, on Linux, you can download the Bicep CLI binary directly from the Bicep releases page.
Installing the templates package
To get started easily, you can install the Bicep.LocalDeploy.Templates package globally:
dotnet new install Bicep.LocalDeploy.TemplatesVerify the installation:
dotnet new list --tag BicepYou should see:
Template Name Short Name Language Tags
---------------------------- --------------- -------- ---------------------------
Bicep Local Deploy Extension bicep-ld-tpl [C#] Bicep/Extension/LocalDeployInstall the documentation CLI
At the end of this module, there will be a lesson on creating documentation. To already prepare you for this lesson, you can install the bicep-local-docgen globally:
dotnet tool install bicep-local-docgen -gVerify the installation:
bicep-local-docgen --versionConfigure your editor
Visual Studio Code (VS Code) is the preferred editor for developing the Bicep Local Deploy extension. It is cross-platform and has a rich extension ecosystem. To install VS Code on the different platforms, use one of the following methods:
For Windows:
# Install VS Code using WinGet
winget install Microsoft.VisualStudioCode
# Launch VS Code
codeFor macOS:
# Install VS Code using Homebrew
brew install --cask visual-studio-code
# Launch VS Code
codeFor Linux (Ubuntu/Debian):
# Download and install VS Code
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list'
rm -f packages.microsoft.gpg
sudo apt-get update
sudo apt-get install code
# Launch VS Code
codeAlternatively, download VS Code directly from code.visualstudio.com for any platform.
Once VS Code is installed, add the following extensions:
# Install C# Dev Kit (C# language support, debugging, project management)
code --install-extension ms-dotnettools.csdevkit
# Install Bicep (Bicep language support, IntelliSense, validation)
code --install-extension ms-azuretools.vscode-bicep
# Install PowerShell (PowerShell scripting support for build scripts)
code --install-extension ms-vscode.powershellUnderstanding the development workflow
Building a Bicep extension follows a structured workflow that takes you from an empty project to a deployable, ready extension. By following this pattern, you can quickly add functionality to an extension while maintaining code quality and documentation. Each step builds on the previous one.
A typical extension development workflow follows these steps:
- Scaffold: Create project from template (or manual).
Start by generating a new extension project using a template. This gives you a pre-configured project structure with sample resources.
- Define: Design resource models with attributes.
Design your resource types by creating C# classes annotated with [ResourceType] and [TypeProperty] attributes. Define what properties your resources will have, which are required or optional, and what outputs they produce. This is where you establish the contract between Bicep and your extension. Add documentation attributes like [BicepDocExample] and [BicepDocHeading] to enrich your API documentation from the start.
- Implement: Code resource handlers and API integration.
Build the business logic by implementing resource handlers that inherit from TypedResourceHandler<TProps, TIdentifiers, TConfig>. Write the code that translates Bicep resource requests into REST API calls. This is where you integrate with external APIs, handle authentication, and manage errors.
- Test: Run locally and validate behavior.
Test your extension by building it locally and deploying it using regular Bicep files. Use the bicep local-deploy command to validate the functionality.
- Document: Generate documentation from attributes.
Generate documentation using the bicep-local-docgen CLI tool. This extracts all metadata from your annotated models and automatically generates Markdown documentation.
- Publish: Publish the extension to a container registry.
Bicep can use a container registry to publish and install extensions. Configure the extension path in your Bicep configuration file, then use it in your Bicep files with the extension keyword.
Quick start: Verify your setup
Now that everything is in place, let's verify everything is installed correctly by creating a test extension:
```bash
# Create a test extension
dotnet new bicep-ld-tpl -n HelloBicep
# Navigate to the project
cd HelloBicep
# Build the extension
.\build.ps1
```dotnet version, update the global.json file with the version you're using.If the build succeeded, your environment is correctly configured, and a new output directory is created with a file in the root of the directory named my-extension.
Next up
Now that you understand the basics and have your environment set up, you're ready to create your first extension. In the next lesson, you'll:
- Explore the template project structure.
- Define custom resource models.
- Implement resource handlers.
- Test your extension with Bicep files.