Jon Gallant
Azure Developer CLI - Origin Story

Azure Developer CLI - Origin Story

7 min read

In 2019, I joined DevDiv with a clear directive from my manager: help improve Azure dev ex. For me, that meant go build apps, feel the pain, make it better.

My title was “E2E Architect.” We had no idea what that meant yet. But after twenty years building software - five as a developer, fifteen leading teams and hands-on coding with customers, I knew exactly what it meant to me.

Find the gaps by experiencing them myself. Not through meetings. Not through specs. But through actual hands-on-keyboard building.

So I built apps on Azure. A lot of them. It wasn’t long before I got inspired to fix things. I immediately hit a wall - 50+ shell scripts just to deploy a single app.

The Problem(s)

A script to provision your resources. Another to deploy your code. Another to run things locally. Last time I counted, I had over 50 scripts for a single app. Death by a thousand shell scripts.

But the deeper problem: there was no way to get a complete solution - infrastructure AND code - up to Azure. You had to stitch together a dozen different tools and figure out how they talked to each other.

The Inspiration

My playground app was memealyzer - a meme sentiment analyzer I built before Open AI existed. Look at the repo and you’ll see provision.sh, deploy.sh, and up.sh. That’s the exact pattern that became azd provision, azd deploy, and azd up.

Here’s the original image I had in my memealyzer project showing how the scripts worked:

Memealyzer Quickstart

If you’ve used azd, you recognize this. The experiments in that repo - dating back to May 2020 - became the Azure Developer CLI.

What I Actually Wanted to Build

After deving Azure solutions for so long I discovered the need for a complete local dev runtime. Not just provision and deploy. I wanted azd to handle:

  • Provision
  • Deploy
  • Run (locally)
  • Test
  • Debug
  • Monitor both Azure and local environments
  • Easy pipeline configuration for both GitHub and Azure DevOps

Everything you need to build an Azure app both locally and in the cloud. A true inner and outer loop solution.

All with simple one word commands, like azd up.

Building the Foundation

My memealyzer scripts were shell scripts - quick and dirty. But as the pattern emerged, I realized we needed something real. We went through the evolution: first a C# prototype, then a Python version as an Azure CLI extension. Both solid approaches, but neither quite fit.

The real constraints were simple:

  • Users shouldn’t have to install the Azure CLI
  • Small and fast
  • No framework dependencies (no Node, no Python)
  • Single binary deployment

It came down to Go or C#. We chose Go - it checks all the boxes and aligns with how the cloud-native community builds tools.

Why the Technical Choices Mattered

Single word commands with convention over configuration was non-negotiable for me. I had a strong preference for very few CLI parameters. Everything should run off convention and config, not random parameters users had to remember. This is why the commands are so simple - azd provision, azd deploy, azd up. Single words that hang off the root azd. No flags to memorize, no configuration matrix to navigate. You run the command, it reads your azure.yaml, and it knows what to do.

YAML for configuration felt right because Docker Compose was using it, Tye was using it. This was before Aspire with strongly typed IaC existing and, at the time, Aspire was .NET-only, and azd had to support every language and framework. That meant requiring a specific language felt like overkill. YAML was the natural fit - language-agnostic and accessible.

Bicep for resources because we didn’t want users dealing with ARM templates directly. They’re verbose and hard to reason about. I worked closely with the Bicep team to make this work. That collaboration directly contributed to what became Azure Verified Modules - a library of best-practice infrastructure templates that teams can use directly in their own azd projects.

Templates for scaffolding - we built azd template so users can get a complete working solution with azd init --template templatename. My original plan was azd up --template - one command to go from template to Azure. That got cut initially, brought back later as azd init --template templatename --up (which, honestly, I still don’t think is a great interface). I still want to bring back the original. Check out aka.ms/awesome-azd for a list of all the community templates.

Shipping and the Feedback Loop

We shipped it. Developers started using it - shipping production apps with it. The Azure samples moved to azd. Issues came in, PRs came in, the feedback loop was real.

I and the team stabilized it - fixing bugs, adding features based on what people were actually doing. Making it production-ready. Getting it into the hands of thousands of developers.

Then I handed it off to the team and moved on to other problems - like Azure MCP and other developer experience work.

Stay Close to Your Tools

I do my best work when I’m using the tools I help build.

After I handed azd off to the team, I moved on to other projects. It’s natural - the product’s solid, the team has it covered. But I should have kept engaged to see the full runtime come to life. To hit the rough edges myself, to understand what’s actually hard, to feel the friction users feel.

I never would have built azd if I wasn’t feeling the pain firsthand - 50+ shell scripts for a single app. That’s where the insights come from: actually doing the work.

So here’s what matters: stay close to the work. That’s where you learn what actually needs to be fixed.

What’s Next for Me and azd

That “Run locally” piece from my original vision never left me. Convention over configuration for your entire development setup. Not just provision and deploy, but actually running your app locally without all the manual prerequisite installation, environment setup, dependency management nonsense.

I wanted to build it. So I started working on azd app.

This is exactly what azd was designed to enable. The power of azd isn’t a monolithic tool that tries to do everything. It’s a platform - core functionality plus extensions that solve specific problems. Developers building what they need. That’s the whole design.

azd app is simple: you run azd app run from your project, and it sets up your environment, installs packages, gets your databases running, configures environment variables, spins up Docker containers. Everything your app needs to run locally. All read from your azure.yaml.

I’m building it the same way I built azd - on my own projects, both Microsoft and personal. Using it daily, hitting the rough edges, fixing them myself. That’s the only real test - am I actually using this thing?

You can try it: github.com/jongio/azd-app. Run azd app run from any azd project. And if you have ideas for extensions you want to build - that’s the whole point of azd.

Thank You

I want to thank everyone who’s used azd. Especially everyone who contributed PRs, filed issues, and made it better. You’ve built some really cool things with it. Watching a POC turn into something thousands of developers use daily - that’s been genuinely rewarding.

Resources


Jon

Share:
Share on X