Kubernetes integration
This article is the reference for the Aspire Kubernetes hosting integration. It enumerates the AppHost APIs — with examples for both AppHost.cs and apphost.mts — that you use to model Kubernetes environment resources in your AppHost project. The integration enables you to publish and deploy your Aspire application to any Kubernetes cluster, generating Helm charts from your application model or deploying directly to a cluster using your current kubectl context.
Installation
Section titled “Installation”To start building an Aspire app with Kubernetes deployment support, install the 📦 Aspire.Hosting.Kubernetes NuGet package:
aspire add kubernetesLearn more about aspire add in the command reference.
Or, choose a manual installation approach:
#:package Aspire.Hosting.Kubernetes@*<PackageReference Include="Aspire.Hosting.Kubernetes" Version="*" />aspire add kubernetesLearn more about aspire add in the command reference.
This updates your aspire.config.json with the Kubernetes hosting integration package:
{ "packages": { "Aspire.Hosting.Kubernetes": "*" }}Add Kubernetes environment
Section titled “Add Kubernetes environment”After installing the package, add a Kubernetes environment to your AppHost:
var builder = DistributedApplication.CreateBuilder(args);
var k8s = builder.AddKubernetesEnvironment("k8s");
var api = builder.AddProject<Projects.MyApi>("api");
builder.Build().Run();import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const k8s = await builder.addKubernetesEnvironment('k8s');
const api = await builder .addNodeApp('api', './api', 'src/index.ts') .withHttpEndpoint({ env: 'PORT' }) .withExternalHttpEndpoints();
await builder.build().run();Configure Helm chart options
Section titled “Configure Helm chart options”You can configure the generated Helm chart using the WithHelm method, which provides a fluent HelmChartOptions builder:
builder.AddKubernetesEnvironment("k8s") .WithHelm(helm => { helm.WithChartName("my-aspire-app") .WithChartVersion("1.0.0") .WithChartDescription("My Aspire application deployed to Kubernetes") .WithReleaseName("my-release") .WithNamespace("my-namespace"); });const k8s = await builder.addKubernetesEnvironment('k8s');await k8s.withHelm(async (helm) => { await helm.withNamespace('my-namespace'); await helm.withReleaseName('my-release'); await helm.withChartName('my-aspire-app'); await helm.withChartVersion('1.0.0'); await helm.withChartDescription('My Aspire application deployed to Kubernetes');});Helm is the default deployment engine. Call WithHelm only when you need to customize the defaults.
The WithHelm method is the single configuration entry point for Helm chart settings. The available options are:
| Method | Description |
|---|---|
WithChartName(string) | Sets the Helm chart name (defaults to the application name). |
WithChartVersion(string) | Sets the Helm chart version. Accepts a literal string or an Aspire parameter. |
WithChartDescription(string) | Sets the description written into Chart.yaml. |
WithReleaseName(string) | Sets the Helm release name used during deployment. |
WithNamespace(string) | Sets the Kubernetes namespace for the deployment. |
Configure a container registry
Section titled “Configure a container registry”A vanilla Kubernetes cluster doesn’t know which container registry to use for your application images. Use AddContainerRegistry and WithContainerRegistry to specify a registry that is accessible from both your local machine and from the cluster:
var registry = builder.AddContainerRegistry("registry", "myregistry.example.com:5000");builder.AddKubernetesEnvironment("k8s").WithContainerRegistry(registry);const registry = await builder.addContainerRegistry('registry', 'myregistry.example.com:5000');const k8s = await builder.addKubernetesEnvironment('k8s');await k8s.withContainerRegistry(registry);Customize individual resources
Section titled “Customize individual resources”Use PublishAsKubernetesService to modify the generated Kubernetes resources for individual services:
using Aspire.Hosting.Kubernetes.Resources;
builder.AddContainer("service", "nginx") .PublishAsKubernetesService(resource => { // Scale to 3 replicas if (resource.Workload is Deployment deployment) { deployment.Spec.Replicas = 3; } });const service = await builder.addContainer('service', 'nginx');await service.publishAsKubernetesService(async (resource) => { // Scale to 3 replicas await resource.workload.spec.replicas.set(3);});Add custom Kubernetes manifests
Section titled “Add custom Kubernetes manifests”Within a PublishAsKubernetesService callback, you can attach arbitrary Kubernetes manifests — such as cert-manager Certificate definitions, additional ConfigMap objects, or any other Kubernetes resource — to the generated Helm chart alongside your service.
The API surface differs by language:
- C#: add subclasses of
BaseKubernetesResourcedirectly to theAdditionalResourcescollection. Several built-in types (such asConfigMap) are available in theAspire.Hosting.Kubernetes.Resourcesnamespace, and you can subclassBaseKubernetesResourceto model any custom resource definition (CRD). - TypeScript: call
addManifeston the resource. It takes the manifest’sapiVersion,kind, andmetadata.name, and returns a handle for setting labels, annotations, a namespace, and arbitrary field values using dot-notation paths.
Define a class for the custom resource by deriving from BaseKubernetesResource, then add an instance to AdditionalResources. The example below models a cert-manager Certificate CRD:
using Aspire.Hosting.Kubernetes.Resources;using YamlDotNet.Serialization;
builder.AddContainer("service", "nginx") .PublishAsKubernetesService(resource => { var certificate = new Certificate { Metadata = { Name = "service-tls" }, Spec = { SecretName = "service-tls", DnsNames = { "service.example.com" }, IssuerRef = { Name = "letsencrypt-prod", Kind = "ClusterIssuer" }, }, }; certificate.Metadata.Labels["example.com/managed-by"] = "aspire"; resource.AdditionalResources.Add(certificate); });
public sealed class Certificate() : BaseKubernetesResource("cert-manager.io/v1", "Certificate"){ [YamlMember(Alias = "spec")] public CertificateSpec Spec { get; set; } = new();}
public sealed class CertificateSpec{ [YamlMember(Alias = "secretName")] public string SecretName { get; set; } = "";
[YamlMember(Alias = "dnsNames")] public List<string> DnsNames { get; } = [];
[YamlMember(Alias = "issuerRef")] public IssuerRef IssuerRef { get; set; } = new();}
public sealed class IssuerRef{ [YamlMember(Alias = "name")] public string Name { get; set; } = "";
[YamlMember(Alias = "kind")] public string Kind { get; set; } = "Issuer";}For simple cases that map to a built-in type, instantiate the type directly — for example, new ConfigMap { Metadata = { Name = "extra-config" }, Data = { ["key"] = "value" } } — and add it to AdditionalResources.
const service = await builder.addContainer('service', 'nginx');await service.publishAsKubernetesService(async (resource) => { await resource.addManifest('cert-manager.io/v1', 'Certificate', 'service-tls', { configure: async (manifest) => { await manifest.withLabel('example.com/managed-by', 'aspire'); await manifest.withField('spec.secretName', 'service-tls'); await manifest.withField('spec.dnsNames', ['service.example.com']); await manifest.withField('spec.issuerRef.name', 'letsencrypt-prod'); await manifest.withField('spec.issuerRef.kind', 'ClusterIssuer'); }, });});The manifest handle returned by addManifest supports the following configuration methods:
| Method | Description |
|---|---|
withNamespace | Sets the Kubernetes namespace for the manifest. |
withLabel | Adds a metadata label to the manifest. |
withAnnotation | Adds a metadata annotation to the manifest. |
withField | Sets an arbitrary field using a dot-notation path (for example, spec.maxReplicaCount). |
Each manifest is emitted as a separate template file inside the generated Helm chart.
Publishing and deployment
Section titled “Publishing and deployment”The Kubernetes integration supports both aspire publish (generate Helm chart artifacts) and aspire deploy (deploy directly to your current cluster context).
For complete walkthroughs, see Deploy to Kubernetes clusters.