Feature: CDK Language Support — Author Azure Infrastructure in Any Programming Language
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
# 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](https://learn.microsoft.com/dotnet/azure/sdk/provisioning/) lets C# developers define Azure resources using the same Azure SDK types they use in their application code. The [Azure CDK](https://github.com/Azure/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):
```csharp
#: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](https://github.com/Azure/azure-cdk) TypeScript API:
```typescript
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: [#7352](https://github.com/Azure/azure-dev/pull/7352) — `provider: 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 forwarding** — `azd 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](https://github.com/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](https://github.com/Azure/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](https://aka.ms/awesome-azd))? Should there be CDK variants of existing templates, or should templates support multiple infrastructure languages side by side?
## Related Work
- **PR [#7352](https://github.com/Azure/azure-dev/pull/7352)** — Working prototype of `provider: code` for C#
- **[Azure.Provisioning](https://learn.microsoft.com/dotnet/azure/sdk/provisioning/)** — C# CDK for Azure resources
- **[Azure CDK Playground](https://github.com/Azure/azure-cdk)** — Web-based authoring environment with IntelliSense
- **[todo-csharp-cosmos-sql-dotnet](https://github.com/m-nash/todo-csharp-cosmos-sql-dotnet)** — Real-world sample template using C# infrastructure (private, can be shared)
Contributor guide
Assessment
This issue has not been assessed yet.