Azure / Azure/azure-dev

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

Open
#7,425 0 comments 0 reactions 0 assignees View on GitHub
area/auth area/provisioning feature
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.