Thursday, June 18, 2026

Microsoft Build: Bicep as a declarative control plane for any system with an API?

 Two weeks ago, I had the privilege of presenting two sessions at Microsoft Build 2026 in San Francisco! I’ve always enjoyed speaking at previous editions of Build, so it was great to be back again. This year, the event moved from Seattle to the beautiful Fort Mason Center in San Francisco. The waterfront location provided an incredible backdrop for a fantastic week of learning, networking, and sharing ideas.

Press enter or click to view image in full size
Fort Mason Center, San Francisco

My first session explored a simple but powerful question:

To demonstrate the concept, I built a custom Bicep Local Deploy extension that controls a physical Zigbee light through Home Assistant. While the light bulb itself was intentionally simple, the goal was much broader: showing how the same Infrastructure as Code principles we use for Azure can be extended to third-party APIs, edge environments, and virtually any platform that exposes a REST API.

The session, “Deploying Infrastructure and Turning on the Light: Bicep Beyond Azure,” was packed with live demos and practical examples. It generated some great discussions afterward and sparked a lot of ideas about what Bicep extensions can enable.

Press enter or click to view image in full size
Deploying Infrastructure and Turning on the Light: Bicep Beyond Azure

The abstract of the session was as follows:

I really enjoyed presenting the session and demonstrating it. The session sparked a lot of ideas in the audience, and I received great feedback afterward.

Subscribe to the Medium newsletter

I also gave away a few copies of my book, as well as some Bicep stickers and pins, which were a great hit!

Press enter or click to view image in full size
Getting started with Bicep — Infrastructure a Code
Press enter or click to view image in full size
Bicep pins and stickers

The demo was structured in three logical steps that demonstrate how Bicep can be extended beyond Azure. In the first step, we built a custom Bicep local-deploy extension by defining a resource model, implementing convergence logic, and creating a client that communicates with Home Assistant to control a Zigbee light.

In the second step, we compiled, published, and packaged the extension so it could be consumed by Bicep as a local extension.

Finally, in the third step, we used the extension from a standard Bicep deployment, where Bicep passed the desired state to the extension, the extension performed the required API calls, and the deployment returned outputs just like any native Azure deployment.

Together, these three steps demonstrate how Bicep can act as a declarative control plane for virtually any platform or system that exposes an API.

To help others get started with Bicep Local Deploy and custom extensions, I’ve published all source code and materials from the session here:https://github.com/fberson/Slidedecks/tree/main/2026/Microsoft%20Build%202026

Here is a quick video of the end result:

Bicep controlling a light via Bicep Local Deploy extensions

Thank you, Chloe Mandell, Melanie McKenna , and the entire team, for making the MVP experience at Microsoft Build such a success!

From the Field: Accelerate Your Development for Microsoft Marketplace!

 🔥 Two weeks ago, I had the privilege of presenting two sessions at Microsoft Build 2026 in San Francisco! I’ve always enjoyed speaking at previous editions of Build, so it was great to be back again. This year, the event moved from Seattle to the beautiful Fort Mason Center in San Francisco. The waterfront location provided an incredible backdrop for a fantastic week of learning, networking, and sharing ideas.

Press enter or click to view image in full size

📍 Before the event started, I spent a few days exploring San Francisco, including an early morning 15km run across the Golden Gate Bridge. Definitely one of the highlights of the trip.

Press enter or click to view image in full size

My session on Microsoft Marketplace was scheduled for Wednesday, just after lunch. The session’s focus was demo-driven and covered the question: how do you take your infrastructure-as-code and turn it into a deployable product experience through the Microsoft Marketplace?

I took the audience on the journey from start to finish as outlined below.

Journey of the session at Microsoft Build

I had the absolute honor of meeting with Elizabeth Beals (McLaughlin) and Felipe Ospina, who reached out prior to the event to sync on the messaging of the Microsoft Marketplace and Build, and exchange ideas.

What I enjoyed most was sharing the lessons learned from real-world projects. The happy path is usually well documented. The validation failures, packaging mistakes, portal UX challenges, and certification surprises are where the real learning happens.

A big thank you to everyone who attended the session, asked questions, shared experiences, and continued the discussion afterward. It was great meeting so many people from around the world who are building on Azure and looking at Microsoft Marketplace as a way to accelerate adoption of their solutions.

One of the coolest additions this year was the physical Microsoft Marketplace on the show floor. It gave attendees a place to ask questions, learn about the latest developments, and continue conversations after sessions. They even had their own Marketplace pins! It also turned out to be the perfect call to action for my talk.

Physical Microsoft Marketplace at Microsoft Build,

Join The Writer's Circle event

Felipe Ospina did a great job presenting on Microsoft Marketplace as well, a session I did not want to miss. He also announced Intelligent Discovery for the Microsoft Marketplace, powered by AI!

Press enter or click to view image in full size

I had the great pleasure of meeting the amazing Kristyn Maddox and Trenton Chavez as well. Great conversations and exchanging of ideas!

For anyone interested in the technical content, Microsoft published the session repository containing the source code, demos, and getting-started guidance: https://github.com/microsoft/Build26-DEM363-from-the-field-accelerate-your-development-for-azure-marketplac

Since a large part of the session focused on Bicep and Infrastructure-as-Code, I also brought a few copies of my book to give away. They disappeared in seconds 😊 You can find the book here https://www.amazon.com/Getting-started-Bicep-Infrastructure-Azure/dp/B098WK3MR7

Press enter or click to view image in full size

A huge thank you to everyone who attended the sessions, asked questions, shared feedback, and continued the discussions afterward.

Events like Build are a reminder that while technology keeps evolving, the best part is still the people you meet and learn from along the way.

I had a blast presenting and attending at Microsoft Build and hope to be back again next year!

Press enter or click to view image in full size

Didn’t attend Microsoft Build and got interested in the session? You can catch the recording here: https://build.microsoft.com/en-US/sessions/DEM363?source=sessions

Press enter or click to view image in full size

Special thanks to Melanie McKenna and Christine Flora (her/she) for taking these pictures! It is always great to see you!

#MSBuild #MVPBuzz

Sunday, March 1, 2026

Deploying Azure Infrastructure… and Turning on the Light


If something has an API and a meaningful desired state, it can be modeled declaratively. That idea feels obvious in the cloud. We describe virtual machines, networks, load balancers, and container apps in code, and the platform converges reality toward that definition. We call it Infrastructure as Code.

But what happens if you apply that same thinking to something in the physical world?

I decided to find out. Using Bicep’s experimental local extension capability, I built a custom resource provider that treats a Home Assistant light as a first-class Infrastructure-as-Code resource. Running az bicep local-deploy now physically changes the state of a Zigbee light in my office, declaratively and idempotently. Not through a script. Not through an automation. Through a resource definition.

Let’s start by seeing it in action in the video below!

Why This Wasn’t Just a Gimmick

Home automation APIs are almost always imperative. You tell them to “turn on,” “turn off,” or “toggle.” That works perfectly for dashboards and mobile apps, but it clashes with Infrastructure as Code principles. IaC is about convergence. You don’t toggle a VM. You declare its desired configuration. You don’t flip a load balancer. You define its final state and let the system move toward it. So my first rule of this extension was simple: no toggle support. A deployment must explicitly declare “on” or “off”. Running the same deployment twice must result in the same outcome. Anything else would undermine the model.

The Real Hardware Behind It

This isn’t simulated. It’s running on actual hardware. Home Assistant is running locally in a VM on Windows 11. For Zigbee connectivity, I’m using the Sonoff ZBDongle-E as the Zigbee 3.0 coordinator. The light itself is an Aqara T2 Light Bulb, capable of RGB and color temperature modes.

The signal path looks like this: Laptop → Home Assistant VM → Zigbee dongle → Aqara bulb

The extension never talks to Zigbee directly. It communicates with Home Assistant via its REST API. Home Assistant handles the radio communication and device state management. That separation is important. The Bicep extension doesn’t care whether the device is Zigbee, Thread, Wi-Fi, or something else. It only cares that the system exposes a stable API and that the resource has a meaningful desired state. Once you abstract at that level, the pattern becomes clean.

The Enabler: Bicep Local Extensions

The experimental local extension model in Bicep allows you to register a custom executable as a resource provider. Instead of deploying to Azure Resource Manager, az bicep local-deploy invokes your handler locally. The execution flow looks like this:

Bicep CLI parses the template. It discovers the registered extension. It invokes the resource handler. The handler performs the operation locally. Outputs are returned to Bicep.

In this case, the handler calls the Home Assistant REST API, applies the declared state, reads back the entity to confirm convergence, and returns outputs. Everything runs locally. Nothing touches Azure. That’s what makes this interesting. Bicep becomes a declarative engine, not just an Azure deployment tool.

Modeling the Light as Infrastructure

Here’s what the resource definition in main.Bicep looks like:

targetScope = 'local'
extension homeassist
@secure()
@description('Home Assistant long-lived access token')
param accessToken string
@description('Home Assistant instance URL')
param homeAssistantUrl string = 'http://192.168.68.70:8123'
@description('The entity ID of the light to control')
param lightEntityId string = 'light.aqara_lumi_light_agl003'
@description('Desired state of the light')
@allowed(['on', 'off'])
param lightState string = 'on'
@description('Brightness level (0-255)')
@minValue(0)
@maxValue(255)
param brightness int = 100
@description('Color temperature mireds (153-500, 0 to skip)')
@minValue(0)
@maxValue(500)
param colorTemp int = 0
@description('Hue 0-360 (-1 to skip)')
@minValue(-1)
@maxValue(360)
param hue int = -1
@description('Saturation 0-100 (-1 to skip)')
@minValue(-1)
@maxValue(100)
param saturation int = -1
resource aqaraLight 'Light' = {
entityId: lightEntityId
homeAssistantUrl: homeAssistantUrl
accessToken: accessToken
state: lightState
brightness: brightness
colorTemp: colorTemp
hue: hue
saturation: saturation
}
output currentState string = aqaraLight.currentState
output friendlyName string = aqaraLight.friendlyName
output entityId string = aqaraLight.entityId

This is the main.bicepparam file, I left out the access token for obvious reasons.

using 'main.bicep'
param accessToken = 'XXX'
param homeAssistantUrl = 'http://192.168.68.72:8123'
param lightEntityId = 'light.aqara_lumi_light_agl003'
param lightState = 'off'
param brightness = 100
param colorTemp = 10
param hue = -1
param saturation = -1

And to be able to import the HomeAssist extension, the following is configured in the bicepconfig.json file. It contains the references to the bin folder where the homeassist extension is located, as well as enabling the localDeploy experimental feature.

{
"experimentalFeaturesEnabled": {
"localDeploy": true
},
"extensions": {
"homeassist": "./bin/bicep-ext-homeassist"
}
}

To kick off the Bicep local deploy run:

az bicep local-deploy main.bicepparam

The Extension Itself

Under the hood, the extension is a .NET 9 resource host that registers a Light resource type and implements CreateOrUpdate semantics. Instead of imperative commands, it computes a desired end state from the template properties and applies exactly one color mode per deployment. It deliberately avoids toggle behavior and enforces idempotency at the handler level. The executable is packaged using az bicep publish-extension and invoked locally through the experimental local-deploy runtime, effectively acting as a custom resource provider, just one that happens to manage a Zigbee bulb instead of a cloud resource.

The Color Mode Lesson

One of the more subtle issues during development was color handling. Home Assistant does not allow color_temp and hs_color in the same service call. Sending both results in an HTTP 400. The extension now enforces exclusivity: if colorTemp is set, it uses color_temp. Otherwise, if hue and saturation are set, it uses hs_color. Never both. It’s a small detail, but it reinforces an important principle: declarative modeling only works when you respect the semantics of the underlying API.

Building and Publishing the Extension

Because this relies on the experimental local extension model, the build and registration steps are important. Here’s the exact build process I use on Windows:

# Restore dependencies
dotnet restore HomeAssistExtension.csproj
# Build
dotnet build HomeAssistExtension.csproj --configuration Release
# Publish self-contained binary
dotnet publish HomeAssistExtension.csproj --configuration Release -r win-x64
# Register with Bicep
az bicep publish-extension `
--bin-win-x64 .\bin\Release\net9.0\win-x64\publish\bicep-ext-homeassist.exe `
--target .\bin\bicep-ext-homeassist `
--force

Dotnet publish produces the executable that implements the resource handlers. az bicep publish-extension packages and registers it locally so Bicep can discover and invoke it during local-deploy. After that, any Bicep file declaring the extension homeassist can use the custom Light resource. It’s Bicep acting as a declarative runtime locally.

Outputs

One of the things I wanted from the beginning was proper deployment feedback — not just “it worked” or “it failed,” but meaningful outputs that reflect the observed state of the device. The Bicep template defines explicit outputs:

output currentState string = aqaraLight.currentState
output friendlyName string = aqaraLight.friendlyName
output entityId string = aqaraLight.entityId

They are returned by the extension itself after it completes the convergence logic. Inside the handler, after calling the appropriate Home Assistant service (light.turn_on or light.turn_off), the extension reads the actual entity state from Home Assistant and maps relevant fields back into the resource outputs.

  • currentState reflects the actual final state reported by Home Assistant.

Surfacing real outputs transforms this from “a script that flips a light” into a proper resource model.

The extension applies the declared desired state, reads back the actual state from the source system, and returns that state as outputs to the Bicep runtime.

It’s being declared, converged, and observed.

And It Doesn’t Stop There

The light was just the smallest possible proof. Through Home Assistant, I already have dishwashers, washing machines, printers, motion sensors, smart plugs, and other appliances integrated behind the same API surface. They all expose the state. They all expose actions. They all have configuration that could be expressed declaratively. More fun challenges ahead!

The extension currently supports lights. But there’s nothing fundamentally preventing it from expanding to switches, scenes, or anything else. Once the extension model exists, the boundary moves.

We’ve been thinking about Infrastructure as Code in terms of where it runs: the cloud, the data center, the platform. Maybe we should start thinking about it in terms of what can converge.

Watching a Bicep deployment turn on a light is fun. Realizing that the same pattern could declaratively manage an entire physical environment is the interesting part.

What’s the most unexpected thing you’d model declaratively?