.NET 9 Aspire — Distributed-App-Composition in der Praxis-Bilanz
Aspire kommt mit .NET 9 als die stabile Antwort auf die ewige Frage, wie man eine Multi-Service-.NET-Anwendung lokal komponiert. Sechs Monate nach dem RTM ist die Bilanz: Im lokalen Dev-Setup ist Aspire ein deutlicher Schritt nach vorne, im Production-Deploy bleibt vieles eigene Verantwortung.
.NET Aspire hat mit der Version 9, die im November 2024 zusammen mit .NET 9 LTS RTM ging, das Preview-Tag verloren und ist sechs Monate später in einer für ein Microsoft-OSS-Projekt erstaunlichen Position: technisch erwachsen, dokumentarisch belastbar, in der .NET-Community akzeptiert — und dennoch in der Production-Bilanz mit einer klaren Lücke. Die kurze Antwort vorab: Aspire ist 2026 der pragmatische Standardweg, eine lokale Multi-Service-.NET-Komposition zu beschreiben. Es ist nicht der Standardweg, sie in Produktion zu betreiben — und das ist auch nicht der Anspruch des Projekts.
Wer Aspire 2026 das erste Mal aufsetzt, hat einen guten Tag. Wer eine bestehende Solution mit drei bis fünf Services, einer PostgreSQL-Instanz, einem Redis-Cache und einem Background-Worker auf Aspire portiert, hat eine intensive Woche. Wer Aspire in eine produktive Kubernetes-Deployment-Pipeline einbettet, hat ein eigenes Projekt — und an dieser Stelle endet die geschenkte Strecke von Aspire.
Was Aspire ist
Aspire ist im Kern dreierlei. Erstens, eine Component-Architektur: kleine NuGet-Pakete (z. B. Aspire.Hosting.PostgreSQL, Aspire.Hosting.Redis, Aspire.Hosting.RabbitMQ), die typisierte Builder-APIs für Infrastruktur-Ressourcen bereitstellen. Zweitens, eine Resource-Definitions-DSL in C#, mit der man die Topologie der Anwendung als Code beschreibt. Drittens, eine Local-Dev-Runtime (Aspire AppHost), die diese Topologie auf dem Entwicklerrechner startet, Service Discovery konfiguriert und ein Dashboard mit OpenTelemetry-Traces, Logs und Metriken anbietet.
Ein typisches Aspire-AppHost-Programm sieht etwa so aus:
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("db")
.WithDataVolume()
.AddDatabase("trace");
var cache = builder.AddRedis("cache");
var queue = builder.AddRabbitMQ("queue");
var api = builder.AddProject<Projects.Trace_Api>("api")
.WithReference(postgres)
.WithReference(cache)
.WithReference(queue);
builder.AddProject<Projects.Trace_Worker>("worker")
.WithReference(postgres)
.WithReference(queue);
builder.AddProject<Projects.Trace_Web>("web")
.WithReference(api)
.WithExternalHttpEndpoints();
builder.Build().Run();
Die DSL ist explizit und in der Praxis sehr lesbar. WithReference(postgres) injiziert dem Zielprojekt die Connection-String-Konfiguration für die PostgreSQL-Instanz, und zwar über die Standard-Konfigurationsbindung von IConfiguration — der Service-Code selbst muss Aspire nicht kennen. Die Trennung zwischen Komposition (AppHost) und Service (das individuelle Projekt) ist sauber und entspricht dem, was die Spring-Boot-3.x-Welt unter dem Begriff „Configuration as Code” macht — mit dem Unterschied, dass Aspire die Konfiguration in C# beschreibt, nicht in YAML.
Service Discovery: stiller Komfort
Die Service-Discovery-Implementierung in Aspire ist eines der Features, die im Dev-Loop am meisten Wert bringen, ohne dass es im Tutorial groß markiert wird. Der Aspire-AppHost startet die Services auf dynamischen Ports, registriert sie in einem internen Naming-Dienst und macht sie über logische Namen erreichbar:
// Im Trace.Web-Projekt:
builder.Services.AddHttpClient<ApiClient>(client =>
{
client.BaseAddress = new Uri("https://api");
});
Die URL https://api wird zur Laufzeit auf den tatsächlichen Endpunkt umgemappt. Das ist denselbe Mechanismus, den Kubernetes über Service-DNS macht — nur eben lokal und ohne dass der Entwickler ein Cluster braucht. Wer schon einmal eine Docker-Compose-Datei für eine .NET-Solution mit fünf Services hingeschrieben hat und in jeder environment-Sektion die ConnectionStrings__...-Variable per Hand bestückt hat, weiß den Komfort zu schätzen.
Im Vergleich zu Tilt.dev — dem in der Go- und Node-Welt verbreiteten Local-Dev-Composer — ist Aspire syntaktisch enger, in der Komposition typisiert (was Compile-Time-Fehler statt YAML-Linting bedeutet) und in der OpenTelemetry-Integration deutlich tiefer. Tilt.dev hat dafür den Vorteil, dass es sprach-agnostisch ist und sich besser an Polyglot-Stacks anpasst. Wer im Team .NET, Node und Python mischt, hat mit Tilt.dev die robustere Antwort. Wer im wesentlichen .NET schreibt und gelegentlich einen Node-Frontend-Container daneben stellt, ist mit Aspire besser bedient.
OpenTelemetry: Aspire als Standardpfad
Aspire integriert OpenTelemetry als Default-Telemetrie-Pfad. Jedes von Aspire gestartete Projekt bekommt automatisch eine OTel-Exporter-Konfiguration, die an das AppHost-Dashboard und optional an externe Collector-Endpunkte sendet. Die Implementation folgt der OpenTelemetry-Spezifikation in Version 1.x und nutzt die OTel-Konventionen für service.name, service.namespace und Resource-Attribute.
Das Dashboard zeigt drei Tabs: Traces, Logs, Metrics. Die Traces-Ansicht ist die wertvollste — sie zeigt verteilte Aufrufe zwischen Services als zusammenhängenden Span-Baum, inklusive HTTP-Statuscodes, EF-Core-Queries (wenn die Aspire-Komponente für EF Core eingebunden ist), Redis-Commands und Outbound-HTTP-Calls. Wer das erste Mal sieht, wie eine POST /orders-Anfrage über drei Services, eine PostgreSQL-Schreibung und einen RabbitMQ-Publish hinweg visualisiert wird, hat einen kleinen Aha-Moment.
Die Schwäche des Dashboards: Es ist als Dev-Tool gedacht, nicht als Produktions-Telemetrie-Frontend. Die Persistenz der Traces ist auf den Lebenszyklus des AppHost begrenzt — wer das Dashboard schließt, verliert die Daten. Für die Produktion bleibt der Standardweg, einen OTLP-Endpoint zu konfigurieren (Grafana Tempo, Jaeger, Honeycomb, Datadog, was auch immer) und Aspire als Quelle anzuschließen. Der Vorteil dabei: Die OTel-Konfiguration der einzelnen Services ist identisch zwischen Dev und Prod — nur der Exporter-Endpoint unterscheidet sich.
Wo Aspire funktioniert
In drei Szenarien zeigt Aspire 2026 seinen Wert deutlich.
Erstens, Multi-Service-Onboarding. Ein neuer Entwickler klont das Repository, öffnet die Solution in Visual Studio 2024 oder Rider 2025.x, drückt F5 — und hat eine lauffähige lokale Umgebung. Vor Aspire hieß das: Docker installieren, drei docker-compose.yaml-Dateien lesen, drei Environment-Files anlegen, die README durchgehen, ein Dutzend docker compose up-Versuche, bis die Port-Konflikte aufgelöst sind. Aspire reduziert das auf einen F5-Druck. Die Onboarding-Zeit für einen neuen Entwickler in einem Aspire-Setup, das ich in den letzten Wochen beobachtet habe: 90 Minuten von Repo-Clone bis erste Pull-Request-Skizze. Das ist ein messbarer Produktivitätsgewinn.
Zweitens, Integrations-Tests mit echter Infrastruktur. Aspire hat einen Test-Host-Modus, in dem das gesamte AppHost-Setup für eine Test-Suite hochgefahren wird. Die Tests laufen gegen echte PostgreSQL-, Redis- und RabbitMQ-Instanzen (in Containern), die Aspire orchestriert. Im Vergleich zu Testcontainers (was als unterliegende Implementierung weiterhin verwendet wird) ist die DSL höher abstrahiert und reduziert die Boilerplate der Test-Setup-Klassen deutlich:
public class OrderApiTests : IClassFixture<DistributedApplicationTestingBuilder>
{
[Fact]
public async Task PlacingOrder_PersistsToDatabase()
{
await using var app = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.Trace_AppHost>()
.BuildAsync();
await app.StartAsync();
var client = app.CreateHttpClient("api");
var response = await client.PostAsJsonAsync("/orders", new { ... });
response.EnsureSuccessStatusCode();
}
}
Drittens, Demo-Setups. Wer einem Kunden, einem Stakeholder oder einem Konferenzpublikum eine Multi-Service-.NET-Anwendung in 30 Sekunden zeigen will, hat mit Aspire das beste Werkzeug. Das Dashboard ist visuell überzeugend und liefert in einem Blick die Architektur, die im Vortrag erläutert wird.
Wo Aspire noch nicht ist
Die Lücke beginnt beim Production-Deploy. Aspire hat eine Aspire.Hosting.Azure-Integration, die per azd up (Azure Developer CLI) eine Aspire-AppHost-Definition in Azure-Container-Apps deployen kann. Das funktioniert, ist aber an die Azure-Plattform gebunden und im Funktionsumfang begrenzt. Für jeden anderen Production-Pfad — selbstgehostetes Kubernetes, AWS ECS, Google Cloud Run, on-prem-Docker — bleibt die Übersetzung von Aspire-Komposition in produktive Infrastruktur-Manifeste eigene Arbeit.
Es gibt das Tool aspirate (Aspirate), ein OSS-Projekt, das aus einer Aspire-Definition Kubernetes-Manifeste generiert. Das ist 2026 aktiv gepflegt, aber explizit kein Microsoft-Produkt und in der Reife nicht auf dem Niveau der AppHost-Runtime selbst. In den drei Aspire-Setups, die ich für diesen Beitrag konsultiert habe, ist die Pipeline durchgängig: Aspire für lokale Entwicklung, manuell gepflegte Kubernetes-Helm-Charts für die Produktion. Die Topologie-Beschreibung existiert damit doppelt — einmal in C# (AppHost), einmal in YAML (Helm) — und das ist die ehrliche Antwort auf die Frage „komponiert Aspire mir die Produktion”: Nein, das macht es nicht.
Microsoft hat in der .NET-Aspire-9-RTM-Ankündigung und in den darauffolgenden Blog-Beiträgen klar gesagt, dass Production-Deployment kein primäres Ziel des Projekts ist. Die Architektur lässt offen, dass Drittanbieter das Lücken-Stück liefern — und das ist konsistent mit der OSS-Strategie. Wer aus dieser Position 2026 ein vollständiges Aspire-to-Production-Tooling erwartet, hat das Projekt missverstanden.
Vergleich: docker-compose und tilt.dev
docker-compose ist der Veteran. Es ist sprach-agnostisch, läuft überall, kennt jeder DevOps-Engineer. Sein Schwachpunkt ist die YAML-Komposition, die für mittlere bis große Topologien schwer wartbar wird, und die fehlende Integration in den Application-Lifecycle der Services. Wer in einem .NET-Projekt eine neue Datenbank-Tabelle anlegt, muss das Service neu builden — docker-compose merkt davon nichts und startet den Container schlicht neu.
Aspire ist hier integrierter. Der AppHost erkennt Code-Änderungen über die normalen Hot-Reload-Mechanismen von .NET 9 und startet Services bei Bedarf neu. Das fühlt sich in der Praxis wie eine durchgehende IDE-Erfahrung an, nicht wie eine zusätzliche Container-Schicht.
tilt.dev ist im sprach-agnostischen Mittelfeld zwischen Compose und Aspire. Es bringt eine Starlark-DSL (eine Python-ähnliche Konfigurations-Sprache), Live-Reload für Container und eine Integration in lokale Kubernetes-Cluster (kind, k3d). Tilt ist die richtige Wahl für Polyglot-Stacks und für Teams, die ihre lokalen Setups so nah wie möglich an Produktion (Kubernetes) halten wollen.
Aspire bleibt die Wahl, wenn das Team .NET-zentriert ist, wenn die Topologie-Definition in der Sprache des Produktes (C#) gewünscht ist und wenn OpenTelemetry-Standardpfade ohne Extra-Konfiguration gefordert sind.
Aspire und EF Core 9: die saubere Integration
Die Aspire-Komponente für EF Core 9 ist eines der Beispiele, in denen die Komposition über die einfache Service-Discovery hinaus Wert bringt. Die Konfiguration in einem Service sieht typisch so aus:
// Trace.Api/Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddNpgsqlDbContext<TraceDbContext>("trace");
var app = builder.Build();
AddNpgsqlDbContext<T> registriert den DbContext, holt die Connection-String aus der Aspire-Konfiguration, registriert Health-Checks gegen die Datenbank und konfiguriert die OpenTelemetry-Instrumentation für EF Core. Drei Konfigurationsschritte, die in einer Pre-Aspire-Welt etwa 20 Zeilen Code waren, in einer Zeile.
Die Health-Check-Integration ist der unsichtbare Teil mit dem höchsten Praxis-Wert. Aspire registriert für jede Ressource Health-Checks, die das AppHost-Dashboard im Status-Tab anzeigt. Wer eine lokale PostgreSQL-Instanz unbeabsichtigt herunterfährt, sieht im Dashboard innerhalb von Sekunden den roten Status — und nicht erst beim nächsten fehlgeschlagenen API-Aufruf zwei Stunden später.
Migration von Compose nach Aspire: was zu erwarten ist
Wer eine bestehende docker-compose-basierte .NET-Solution auf Aspire portiert, sollte mit einer Woche Arbeit pro Service rechnen. Die wesentlichen Schritte sind:
Erstens, AppHost-Projekt anlegen (dotnet new aspire-apphost). Das ist ein Konsolenprojekt mit einer Program.cs, die die Komposition beschreibt.
Zweitens, Komponenten-Pakete hinzufügen. Die NuGet-Pakete für PostgreSQL, Redis, RabbitMQ etc. müssen referenziert werden — sowohl im AppHost (für das Hosting) als auch in den jeweiligen Service-Projekten (für die Client-Integration).
Drittens, Service-Projekte refaktorisieren. Die Service-Projekte müssen ihre Konfigurations-Logik so anpassen, dass sie die Aspire-Konventionen nutzen — also nicht mehr manuell ConnectionStrings:DefaultConnection lesen, sondern builder.AddNpgsqlDbContext<T>(...) verwenden.
Viertens, Dashboards und Tooling. Die OTel-Konfiguration der Services muss konsolidiert werden. In den meisten Fällen heißt das: bestehende OTel-Setups entfernen, weil Aspire sie ersetzt.
Fünftens, die Production-Pipeline parallel pflegen. Die docker-compose-Files für Production-Deploy bleiben in den meisten Setups bestehen, sind aber jetzt in Aspirate-generierter Form oder als manuell gepflegte Manifeste vorhanden. Die Doppelpflege ist die ehrliche Antwort auf das, was Aspire 2026 nicht löst.
Bilanz
Aspire ist sechs Monate nach .NET 9 RTM ein erwachsenes Lokal-Dev-Werkzeug. In der spezifischen Frage, die es lösen soll — die Komposition einer Multi-Service-.NET-Anwendung auf dem Entwickler-Rechner — ist es 2026 die beste verfügbare Antwort. Die Onboarding-Zeit für neue Entwickler sinkt messbar, die Konfigurations-Drift zwischen Dev-Setups einzelner Teammitglieder geht gegen null, und die OpenTelemetry-Integration ist ein angenehmer Standard, der ohne Extra-Aufwand mitkommt.
Die Production-Lücke ist real und wird voraussichtlich nicht durch Microsoft selbst geschlossen werden. Wer Aspire in einer .NET-9-Codebase einführt, sollte das mit der bewussten Akzeptanz tun, dass die Produktions-Deployment-Pfade weiterhin in der eigenen Verantwortung liegen — und dass die Topologie-Definition damit doppelt existiert. Für die meisten Teams ist dieser Preis akzeptabel, weil der lokale Komfort den Doppelpflege-Aufwand überwiegt. Für Teams mit sehr volatilen Topologien oder mit einer Polyglot-Architektur ist die Rechnung weniger eindeutig.
Die nächsten 12 Monate werden voraussichtlich bringen, dass die Aspirate-Toolchain reift, dass weitere Komponenten-Pakete für seltene Infrastruktur-Bausteine erscheinen (Kafka ist 2026 abgedeckt, NATS und ScyllaDB noch nicht in der ersten Reihe) und dass die Integration in Visual Studio und Rider weiter verfeinert wird. Strukturelle Änderungen am Aspire-Modell sind nicht absehbar — was angesichts der aktuellen Reife eine gute Nachricht ist.
Wer im Mai 2026 ein neues .NET-9-Multi-Service-Projekt startet, sollte mit Aspire anfangen. Wer eine bestehende, produktiv stabile Lösung mit eingespielten Compose- oder Helm-Setups hat, sollte den Aufwand der Portierung gegen den lokalen Komfortgewinn abwägen — und in vielen Fällen ist die Antwort: lohnt sich, aber nicht in dieser Woche.