Skip to content

Feature: CDK Language Support — Author Azure Infrastructure in Any Programming Language #7425

@m-nash

Description

@m-nash

Feature: CDK Language Support — Author Azure Infrastructure in Any Programming Language

Summary

Enable developers to define their Azure infrastructure in general-purpose programming languages (C#, TypeScript/JavaScript, Python, Go, etc.) and have all azd commands work transparently. Customers should never need to know about or care about Bicep — they simply author their infrastructure in the CDK language of their choice, and azd init, azd up, azd provision, azd provision --preview, azd deploy, azd down, etc. all just work.

Motivation

Today, azd supports two infrastructure-as-code options: Bicep and Terraform. While powerful, both are domain-specific languages that require developers to learn specialized syntax. Many developers would prefer to define their infrastructure using the same programming languages they already use for their application code.

Cloud Development Kits (CDKs) make this possible by letting developers use familiar languages and tooling — IDE IntelliSense, type checking, debugging, refactoring, testing, and package management — to define infrastructure. The CDK compiles to an intermediate representation (like Bicep or ARM templates) that cloud platforms understand.

Azure already has this capability: Azure.Provisioning lets C# developers define Azure resources using the same Azure SDK types they use in their application code. The Azure CDK project is extending this to TypeScript/JavaScript. Other languages can follow the same pattern.

The gap is in azd — there's no way to point azd at a .cs or .js file in your infra/ folder and have it just work. This proposal would close that gap.

User Experience

What it looks like today (Bicep only)

my-app/
├── src/           # Application code
├── infra/
│   ├── main.bicep              # Must learn Bicep DSL
│   ├── main.parameters.json
│   └── modules/
│       ├── cosmos.bicep
│       └── appservice.bicep
└── azure.yaml

What it should look like (CDK — C# example)

my-app/
├── src/           # Application code
├── infra/
│   └── infra.cs   # Write infrastructure in C# — that's it
└── azure.yaml

Where infra.cs uses .NET 10 single-file app support (no .csproj needed):

#:package Azure.Provisioning.Resources@1.0.0
#:package Azure.Provisioning.Storage@1.0.0

using Azure.Provisioning;
using Azure.Provisioning.Resources;
using Azure.Provisioning.Storage;

var infra = new Infrastructure("helloStorage");

var rg = new ResourceGroup("rg");
infra.Add(rg);

var storage = new StorageAccount("storage")
{
    Kind = StorageKind.StorageV2,
    Sku = new StorageSku { Name = StorageSkuName.StandardLrs },
};
rg.Add(storage);

infra.Build().Save(args[0]);

What it should look like (CDK — TypeScript example)

my-app/
├── src/           # Application code
├── infra/
│   └── infra.ts   # Write infrastructure in TypeScript
└── azure.yaml

Where infra.ts uses the Azure CDK TypeScript API:

import { resourceGroup, stack } from "@azure-cdk/core";
import { storageAccount } from "@azure-cdk/storage";

const infra = stack({ name: "helloStorage", targetScope: "subscription" });

const rg = resourceGroup(infra, { location: "eastus" });

const storage = storageAccount(rg, {
  sku: { name: "Standard_LRS" },
});

All azd commands should work

Command Behavior
azd init Detect CDK files in infra/, scaffold azure.yaml accordingly
azd up Compile CDK → intermediate → deploy to Azure
azd provision Same as above, infra only
azd provision --preview Compile CDK → show what-if diff
azd deploy Deploy application code to provisioned resources
azd down Tear down all resources
azd provision -- --param value Forward parameters to the CDK program

Proof of Concept

We've built a working prototype for C# / Azure.Provisioning that demonstrates this is viable:

PR: #7352provider: code provisioning provider

  • CodeProvider — language-agnostic router that detects the CDK language from file extensions in /infra and dispatches to language-specific sub-providers
  • DotNetProvider — compiles C# to Bicep via dotnet run, then delegates to the existing BicepProvider for deployment
  • Auto-detection — drop a .cs file in /infra, azd detects it automatically (no explicit provider: config needed in azure.yaml)
  • Single-file support — uses .NET 10 file-based apps with #:package directives, no .csproj required
  • Parameter forwardingazd provision -- --region westus3 --prefix myapp passes args through to the C# program
  • Alpha-gated — behind azd config set alpha.code on

Real-World Validation

We converted the todo-csharp-cosmos-sql sample template from Bicep to a single infra/infra.cs file: m-nash/todo-csharp-cosmos-sql-dotnet

  • 7 Azure resources: Cosmos DB (serverless, NoSQL), App Service Plan, Web App, API App, Key Vault, App Insights, RBAC
  • Full E2E verified: azd up → API responds → Playwright tests pass → azd down cleans up
  • Same app code, same tests — only the /infra folder changed

Azure CDK Playground

The Azure CDK project provides a web playground where users can write infrastructure in C# (and soon TypeScript) with full IntelliSense, see the compiled Bicep/JSON output in real-time, and get error diagnostics with line attribution — demonstrating the authoring experience.

Architecture

The proposed architecture uses a compilation step that converts CDK code to an intermediate representation before deployment:

CDK Source (.cs, .ts, .js, .py)
    ↓  [language-specific compiler]
Intermediate Representation (Bicep / ARM JSON)
    ↓  [existing azd deployment pipeline]
Azure Resources

This approach:

  • Leverages existing azd infrastructure — all deployment, state management, and resource tracking reuse the proven Bicep/ARM pipeline
  • Is language-extensible — adding a new CDK language means implementing a compiler adapter, not a new deployment pipeline
  • Keeps Bicep as a supported first-class option — this is additive, not a replacement

Open Questions

1. Core Provider vs Extension

There are two viable implementation approaches:

Core Provider (current PR #7352 approach):

  • New ProviderKind in provider.go with CodeProvider routing to language sub-providers
  • All azd commands work natively including --preview, parameter forwarding
  • Requires changes to azd core; ships with azd releases

azd Extension (suggested by @vhvb1989):

  • Use ServiceTargetProvider extension API to implement compilation + deployment
  • Ships independently from azd releases; no core changes needed
  • Extension handles Package() (compile CDK → Bicep) and Deploy() (deploy Bicep to Azure)

The extension approach may need some platform support to ensure all commands work seamlessly (e.g., --preview support, parameter forwarding). What's the preferred direction?

2. Language Onboarding

How should new CDK languages be added? The current architecture has a CodeProvider router that could dispatch based on file extension:

  • .cs / .csproj → .NET / Azure.Provisioning
  • .ts / .js → TypeScript/JavaScript / Azure CDK
  • .py → Python (future)
  • .go → Go (future)

Should each language be a separate azd extension, or should there be a single "CDK" extension/provider that bundles supported languages?

3. azd init Integration

When a user runs azd init, should there be an option to choose their CDK language? For example:

? Select your infrastructure language:
  > Bicep
    C# (Azure.Provisioning)
    TypeScript
    Terraform

4. Template Ecosystem

How should CDK-based templates be represented in the template gallery (aka.ms/awesome-azd)? Should there be CDK variants of existing templates, or should templates support multiple infrastructure languages side by side?

Related Work

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions