Every Aspire release since 13.0 has nudged the project further from "local development tool" towards "full deployment platform." But there was always a conspicuous gap in the story: Kubernetes. You could deploy to Azure Container Apps with a single command, but if your production target was a Kubernetes cluster — and for many teams, it is — you were back to hand-writing Helm charts or reaching for third-party tools like Aspir8. Aspire 13.3 closes that gap.
Released on 7 May 2026, this update ships a Helm-based Kubernetes deployment engine, browser telemetry streaming for frontend resources, three distinct JavaScript publishing models, and the one command everybody has been asking for: aspire destroy. It is a dense release — 45 new features, 134 improvements, and 93 bug fixes — so let us focus on the changes that will reshape how you build and deploy distributed applications.
Kubernetes deployment with Helm
The headline feature is AddKubernetesEnvironment. Declare it in your AppHost, run aspire deploy, and the CLI generates a complete Helm chart, builds and pushes your container images, and applies the chart against your cluster — no separate helm install, no kustomize, no hand-rolled YAML.
var builder = DistributedApplication.CreateBuilder(args);
var k8s = builder.AddKubernetesEnvironment("k8s");
var cache = builder.AddRedis("cache");
var api = builder.AddProject<Projects.Api>("api")
.WithReference(cache)
.WithComputeEnvironment(k8s);
var web = builder.AddProject<Projects.Web>("web")
.WithReference(api)
.WithComputeEnvironment(k8s);
builder.Build().Run();
That is all the AppHost code you need. When you run aspire deploy, the CLI walks the resource graph, generates Kubernetes manifests for each project, wraps them in a Helm chart, and runs helm upgrade --install against the currently configured kubectl context. Config values, connection strings, and service references are injected as environment variables through Helm values — no manual wiring required.
If you want control over namespace and release names:
var k8s = builder.AddKubernetesEnvironment("k8s")
.WithHelm(options =>
{
options.Namespace = "production";
options.ReleaseName = "myapp-prod";
});
The TypeScript AppHost equivalent works identically:
const k8s = await builder.addKubernetesEnvironment('k8s');
const cache = await builder.addRedis('cache');
const api = await builder.addProject('api', '../Api/Api.csproj');
await api.withReference(cache);
await api.withComputeEnvironment(k8s);
// WARNING
Kubernetes deployment is in preview in 13.3. The API surface is stable enough for staging environments, but expect refinements in subsequent releases.
Ingress and Gateway API routing
Deploying containers is only half the story. You also need to route traffic into your cluster. Aspire 13.3 introduces first-class Ingress and Gateway API resources that you declare directly in the AppHost:
var k8s = builder.AddKubernetesEnvironment("k8s");
var api = builder.AddProject<Projects.Api>("api")
.WithComputeEnvironment(k8s);
var ingress = k8s.AddIngress("public")
.WithIngressClass("nginx")
.WithHostname("api.example.com")
.WithTls("api-cert");
ingress.WithRoute("/", api.GetEndpoint("http"));
When aspire deploy runs, it generates the corresponding Ingress, IngressClass, and cert-manager Certificate resources. If your cluster uses the newer Gateway API instead, the generated manifests use Gateway and HTTPRoute resources instead — same AppHost code, different cluster configuration.
This is a significant productivity gain. The Ingress and cert-manager YAML alone typically account for a third of the manifest boilerplate in a typical microservice deployment.
Browser telemetry streaming
Server-side telemetry has been Aspire's strength since day one. But frontend applications have always been a blind spot — your API logs flow neatly into the dashboard while your React or Vue app's console errors disappear into a browser tab nobody is watching.
The new WithBrowserLogs() extension from the Aspire.Hosting.Browsers package changes that. Attach it to any frontend resource, and Aspire captures console logs, network requests, and errors from a Chromium instance, streaming them into the dashboard alongside your server-side telemetry:
var frontend = builder.AddViteApp("frontend", "../frontend")
.WithHttpEndpoint(port: 3000)
.WithBrowserLogs();
The dashboard shows these logs in the same resource log view you already use for backend services. You get a unified timeline of what happened on the server and what happened in the browser — invaluable when debugging a failed API call that only manifests as a silent network error on the client.
// NOTE
WithBrowserLogs() is experimental in 13.3. The compiler will emit diagnostic ASPIREBROWSERLOGS001 — suppress it explicitly if you want to opt in.
Command results and the notification centre
Aspire has supported custom resource commands since 13.1 — buttons in the dashboard that trigger actions on your resources. But the results were fire-and-forget: you clicked, it ran, and you hoped it worked. In 13.3, commands return structured results that surface in a new dashboard notification centre.
builder.AddProject<Projects.Api>("api")
.WithCommand(
name: "issue-access-token",
displayName: "Issue Access Token",
executeCommand: context =>
{
var token = Convert.ToBase64String(
RandomNumberGenerator.GetBytes(32));
return Task.FromResult(CommandResults.Success(
message: "Access token issued.",
result: token,
resultFormat: CommandResultFormat.Text));
});
When you click "Issue Access Token" in the dashboard, the result appears as a timestamped notification with a "View response" action. The notification centre renders markdown, so you can return formatted output. JSON results get syntax highlighting.
HTTP commands also support result modes. If you have a health-check or sync endpoint, you can surface its response directly:
builder.AddProject<Projects.Api>("api")
.WithHttpCommand("/admin/sync", "Sync now", commandOptions: new()
{
ResultMode = HttpCommandResultMode.Auto
});
The Auto mode inspects the response content type and formats accordingly. For CI/CD pipelines, the CLI pipes command results to stdout, so you can script against them.
Three ways to publish JavaScript
Aspire's JavaScript story has been "add a Node app and hope for the best" for too long. Version 13.3 introduces three explicit publishing models, each targeting a different deployment pattern:
Static websites for SPAs that produce a dist/ folder:
builder.AddViteApp("web", "./web")
.PublishAsStaticWebsite(apiPath: "/api", apiTarget: api);
This publishes static assets and configures a YARP reverse proxy to forward /api requests to your backend service — a pattern so common it deserves dedicated support.
Node servers for SSR frameworks that bundle to a single entry point:
builder.AddViteApp("web", "./web")
.PublishAsNodeServer(
entryPoint: ".output/server/index.mjs",
outputPath: ".output");
This copies only the build output, not node_modules. It is ideal for frameworks like Nuxt in standalone mode or SvelteKit with the Node adapter.
npm scripts for frameworks that need node_modules at runtime:
builder.AddNodeApp("app", "./app")
.PublishAsNpmScript();
And for Next.js specifically, there is a dedicated helper that sets up standalone output mode automatically:
builder.AddNextJsApp("web", "./web");
// TIP
Aspire now auto-detects your package manager from lockfiles. If it finds bun.lock, it uses Bun. yarn.lock triggers Yarn. pnpm-lock.yaml triggers pnpm. No configuration needed.
The CLI learns to clean up
The most requested CLI feature was always "undo what aspire deploy did." The new aspire destroy command does exactly that:
aspire destroy
It reads the same AppHost configuration that aspire deploy used, identifies the provisioned resources, and tears them down. For Kubernetes deployments, it runs helm uninstall. For Azure, it removes the resource group. For Docker Compose, it runs the equivalent of docker compose down.
This is transformative for ephemeral environments. You can spin up a full preview environment in a pull request pipeline, run your integration tests, and clean up afterwards — all with CLI commands that understand your application's resource graph.
Standalone dashboard
The dashboard no longer requires an AppHost. You can run it in standalone mode and point any application's OTLP telemetry at it:
aspire dashboard run
This is useful when you want Aspire's dashboard for applications that do not use Aspire's AppHost — a legacy service, a non-.NET application, or a production monitoring scenario. Any application that exports OTLP telemetry can send it to the standalone dashboard.
Other CLI additions
A few smaller but welcome additions:
aspire docs api search "WithReference"searches Aspire's API documentation from the terminal--list-stepspreviews the deployment pipeline without executing it- Pipeline step summaries show duration and success/failure for each stage
check-container-runtimefails fast when Docker or Podman is unavailable, instead of failing halfway through resource creation
Entity Framework Core in the AppHost
A new Aspire.Hosting.EntityFrameworkCore package brings EF Core migration management directly into the dashboard and CLI. Six new commands let you list, apply, revert, and create migrations without leaving the Aspire workflow:
builder.AddProject<Projects.Api>("api")
.WithEntityFrameworkMigrations();
The dashboard displays migration status badges on the resource, and the CLI exposes the same commands for scripting. This eliminates the common pattern of shelling out to dotnet ef in deployment scripts — the migration lifecycle is now part of the same pipeline as the rest of your infrastructure.
Common pitfalls
Mixing compute environments within a dependency chain. If service A references service B, both need to target the same compute environment (or A needs a public endpoint to reach B). Aspire does not automatically bridge between a Kubernetes cluster and Azure Container Apps.
Forgetting WithComputeEnvironment for a resource. Resources without a compute environment assignment are skipped during aspire deploy. If your API deploys but your background worker does not, check that both call WithComputeEnvironment(k8s).
Expecting WithBrowserLogs() to work in production. Browser telemetry uses a Chromium instance managed by Aspire's development orchestrator. It is a development-time feature, not something you deploy alongside your application.
Using aspire destroy without checking the target. The command reads your current AppHost configuration and kubectl context. If you have switched branches or kubectl contexts since your last deploy, verify where aspire destroy will actually run before executing it.
Ignoring breaking changes from 13.2. The --log-level CLI flag is now --pipeline-log-level. The dashboard MCP server has been replaced with aspire agent init. If your CI/CD pipelines use these flags, update them before upgrading.
Summary
Aspire 13.3 represents a meaningful shift in what Aspire can do beyond local development:
- Kubernetes deployment is now a first-class citizen, with Helm chart generation, Ingress/Gateway API routing, and AKS-specific node pool configuration
- Browser telemetry surfaces frontend console logs and network requests alongside server-side traces in the dashboard
- JavaScript publishing provides three distinct models — static websites, Node servers, and npm scripts — each targeting a specific deployment pattern
- Command results make custom resource commands actionable, with structured output in the dashboard notification centre and stdout in the CLI
aspire destroycompletes the deployment lifecycle, enabling proper ephemeral environment workflows- EF Core integration brings migration management into the AppHost, dashboard, and CLI
The Kubernetes support is the standout feature. It is still in preview, but the direction is clear: Aspire wants to be the single tool that takes your distributed application from F5 to production, regardless of whether production means Azure Container Apps, Kubernetes, or Docker Compose.