What Aspire 9 Did Well
.NET Aspire 9 solved a real problem: locally orchestrating distributed .NET applications was painful. Running multiple services, a database, a message broker, and a frontend simultaneously meant juggling scripts, docker-compose files, and manually configured environment variables.
Aspire 9 introduced the AppHost – a C# project that describes the entire application structure as code:
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("db");
var api = builder.AddProject<Projects.Api>("api")
.WithReference(postgres);
var frontend = builder.AddProject<Projects.Frontend>("frontend")
.WithReference(api);
builder.Build().Run();
Local development, service discovery, the integrated dashboard for logs and traces – all of that worked well. The AppHost knew which services depended on each other, set connection strings automatically, and started everything in the right order.
The problem began the moment you wanted to actually deploy that locally working application somewhere.
The Deployment Problem in Aspire 9
The Primary Path: azd and Azure Container Apps
The official and fully supported deployment model in Aspire 9 ran through the Azure Developer CLI (azd). You generated a manifest – a JSON file describing all resources and their connections as a static snapshot – and handed it to azd, which translated it into Azure Bicep templates and provisioned everything as Azure Container Apps.
azd up
For Azure, this was a working path. Anyone running AWS, GCP, or their own infrastructure found nothing comparable in the official documentation. The manifest was theoretically readable by other tools, but that was self-initiative – not a supported workflow.
The Manifest Model and Its Structural Limits
The manifest was a static snapshot of the AppHost model at generation time. Complex dependencies, conditional configurations, or resources that receive concrete values only at runtime – none of that could be fully expressed in a static JSON document. What worked locally in the AppHost sometimes had to be simplified or omitted when exported to the manifest.
On top of that: every azd up started from zero. The tool had no memory of the last subscription, region, or resource group used. Anyone deploying regularly answered the same questions on every run.
Kubernetes: Helm Charts Yes, Deploying No
Starting with Aspire 9.2 (April 2025), Aspire.Hosting.Kubernetes provided an official Kubernetes publisher – but as a preview, and with one critical limitation: it could generate Helm charts, but not deploy them.
The publisher produced a complete Helm chart structure from the AppHost:
Chart.yaml ← metadata
values.yaml ← configuration parameters
templates/
deployment.yaml ← per service
service.yaml
configmap.yaml
secret.yaml
The next step – helm install or helm upgrade against a real cluster – was entirely the developer's responsibility. aspire deploy for Kubernetes did not exist anywhere in the 9.x series. There was a gap right in the middle of the workflow.
Concrete bugs made practical use harder still. Port fields were serialized as strings instead of int32, causing helm upgrade to fail. Init containers – for database migrations, for example – were not correctly included in the generated manifests. The central values.yaml required manual --set overrides at deployment time because configuration was not embedded directly in ConfigMaps or Secrets.
Docker Compose was also available as a publisher from 9.2 onwards, but likewise only as a preview and without aspire deploy support.
The Community as a Stop-Gap: aspirate
Because the official Kubernetes path was incomplete, the community built aspirate (also known as Aspir8). It read the Aspire manifest and handled what the official publisher left out: registry push, secret management, and direct cluster deployment via aspirate apply.
aspirate worked, but it was a workaround. Updates lagged behind Aspire's development, and new Aspire features took time to reach the community tool.
The fact that a community tool was needed for something as fundamental as Kubernetes deployment said a lot about Aspire 9's limits.
Summary: What Aspire 9 Lacked
- Azure Container Apps was the only fully supported deployment target
- Kubernetes: Helm chart generation possible (preview from 9.2), but no
aspire deploy– manualhelm installrequired - Docker Compose: publisher available (preview from 9.2), but no complete deploy path
- Azure App Service: only available from 9.3 as a preview, not stable
- No AWS, no GCP, no on-premises – neither officially nor designed for extensibility
- Static manifest model with no state memory and structural expression limits
- No extension model for custom deployment targets
How Aspire 13 Changed That
13.0 – The Foundation: Pipeline Model and State Persistence (November 2025)
The biggest change was architectural. The manifest-based publisher model was fully replaced by a pipeline model: each resource in the AppHost contributes its own PipelineStep objects, which declare dependencies on each other, run in parallel where possible, and are observable as individual units. The old APIs (IDistributedApplicationPublisher, WithPublishingCallback, PublishingContext) were removed.
aspire deploy # or: aspire do deploy
For the first time, Aspire remembered state between deployments: subscription, resource group, region, and parameter values are saved per developer and environment and pre-filled on the next run.
Stably supported in 13.0 were Azure Container Apps and Azure App Service. Docker Compose and Kubernetes were present but still in progress.
13.1 – Container Registry and Docker Compose Deploy (December 2025)
Container registries became a standalone concept in the AppHost in 13.1:
var registry = builder.AddContainerRegistry("myregistry", "registry.example.com");
var api = builder.AddProject<Projects.Api>("api")
.WithContainerRegistry(registry);
Instead of being implicitly tied to an Azure Container Registry, the registry could now be separately provisioned, reused, or pointed at external registries (Docker Hub, GHCR). The deployment pipeline gained an explicit push step that could run in parallel with other steps.
Docker Compose received full deploy support for the first time in 13.1 – aspire deploy worked end-to-end without any manual Docker CLI intervention.
Azure App Service gained deployment slots: zero-downtime deployments via a staging slot and automatic swap were configurable directly from the AppHost.
13.2 – Docker Compose Reaches Stable, Azure Network Isolation (March 2026)
Docker Compose left preview status in 13.2 and became stable. For the first time there was a fully supported, non-Azure deployment path.
New infrastructure-as-code APIs for network isolation in Azure deployments were added:
builder.AddAzureVirtualNetwork("vnet")
.AddSubnet("app-subnet")
.AddPrivateEndpoint(postgres);
Azure Virtual Networks, private endpoints with automatic DNS zone configuration, and network security groups could be declared directly in the AppHost. Kubernetes also received YAML serialization bugfixes that had caused helm upgrade failures in 9.x.
13.3 – End-to-End Kubernetes, AKS, and aspire destroy (May 2026)
The decisive step for Kubernetes: aspire deploy now worked fully against real clusters. The workflow ran through helm install or helm upgrade under the hood – without manual intervention. aspire destroy correspondingly ran helm uninstall and removed namespaces.
Azure Kubernetes Service (AKS) got its own hosting package (Aspire.Hosting.Azure.Kubernetes):
builder.AddAzureKubernetesEnvironment("prod-aks")
.WithHelm();
Aspire generated a combined Bicep and Helm pipeline: cluster provisioning, image push, and Helm deployment in a single run. Ingress and Gateway API became first-class concepts – routing rules, TLS termination via cert-manager, and FQDN assignment could be expressed directly in the AppHost without separate Kubernetes YAML files.
13.4 – General Availability and External Helm Charts (June 2026)
With 13.4, aspire publish, aspire deploy, and aspire destroy left preview status. Kubernetes support gained cert-manager with Let's Encrypt integration as a typed API, as well as Azure Application Gateway for Containers (AGC) for AKS deployments.
New: AddHelmChart allows installing arbitrary external Helm charts as part of the deployment pipeline:
builder.AddHelmChart("nginx-ingress", "ingress-nginx/ingress-nginx", "4.10.0");
This means custom Aspire resources can be deployed alongside standard ecosystem charts (ingress controllers, monitoring stacks) without leaving the pipeline.
Still not officially supported: AWS, GCP, and on-premises deployments. The pipeline model is extensible via WithPipelineStepFactory, but custom providers must be fully built from scratch.
Need Support?
Evaluating Aspire for your project or planning a migration from Aspire 9 to 13, but unsure which deployment path fits your infrastructure? We're happy to help! Just contact us via our contact page and we'll work together to find the right Aspire strategy for your setup.

