.NET Aspire ā Cloud-Native Apps Without the Boilerplate
Discover .NET Aspire: a new opinionated stack for building observable, production-ready .NET cloud applications. Learn the App Host, service discovery, components, and the dev dashboard.
.NET Aspire
.NET Aspire is an opinionated, cloud-ready stack for building distributed .NET applications. It solves the boilerplate problem: service discovery, health checks, telemetry, and local orchestration ā configured once, works everywhere.
What Problem Does Aspire Solve?
Building a distributed app typically means manually wiring up:
- Service discovery (how does Service A find Service B?)
- Connection strings (hard-coded or environment variables?)
- Distributed tracing (OpenTelemetry, but how to configure?)
- Health checks (each service defines its own)
- Local dev (Docker Compose, manual ports, remembering which service to start first)
Aspire handles all of this from a single App Host project.
The Three Aspire Projects
MyApp.AppHost ā orchestrates everything; defines the distributed app
MyApp.ServiceDefaults ā shared defaults: telemetry, health checks, service discovery
MyApp.ApiService ā your actual service (references ServiceDefaults)
MyApp.Web ā Blazor/React frontend (references ServiceDefaults)Setup
dotnet workload install aspire
dotnet new aspire-starter -n MyAppOr add Aspire to an existing solution:
dotnet new aspire-apphost -n MyApp.AppHost
dotnet new aspire-servicedefaults -n MyApp.ServiceDefaultsApp Host ā Orchestrating Services
// MyApp.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
// Add a Redis cache
var cache = builder.AddRedis("cache");
// Add a PostgreSQL database
var db = builder.AddPostgres("postgres")
.AddDatabase("mydb");
// Add the API service, inject the cache and DB as dependencies
var api = builder.AddProject<Projects.MyApp_ApiService>("api")
.WithReference(cache)
.WithReference(db);
// Add the frontend, inject the API endpoint
builder.AddProject<Projects.MyApp_Web>("webfrontend")
.WithReference(api)
.WithExternalHttpEndpoints();
builder.Build().Run();When you run the AppHost, Aspire starts Redis and PostgreSQL in Docker, starts both .NET projects, and wires up all connection strings automatically.
Service Defaults ā Shared Configuration
// MyApp.ServiceDefaults/Extensions.cs (generated)
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(
this IHostApplicationBuilder builder)
{
// OpenTelemetry ā traces, metrics, logs
builder.ConfigureOpenTelemetry();
// Health checks ā /health and /alive endpoints
builder.AddDefaultHealthChecks();
// Service discovery
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
http.AddServiceDiscovery();
http.AddStandardResilienceHandler(); // retries + circuit breaker
});
return builder;
}
}Every service calls builder.AddServiceDefaults() ā one line gets you telemetry, health checks, and resilient HTTP clients.
Service Discovery in Action
// In the frontend (MyApp.Web/Program.cs)
builder.AddServiceDefaults();
// Register a typed HTTP client pointing to the API by name
builder.Services.AddHttpClient<ApiClient>(
client => client.BaseAddress = new Uri("https+http://api")); // "api" matches AppHost nameNo hard-coded URLs. Aspire injects the actual address at runtime based on whether you're in local dev, Docker, or Kubernetes.
Aspire Components
Aspire provides pre-built integration packages that configure services with best practices baked in:
dotnet add package Aspire.StackExchange.Redis
dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Aspire.Azure.Storage.Blobs
dotnet add package Aspire.Azure.Messaging.ServiceBus// In your service (Program.cs)
builder.AddServiceDefaults();
// Redis ā auto-configured, connection string injected by AppHost
builder.AddRedisDistributedCache("cache");
// PostgreSQL + EF Core ā auto-configured
builder.AddNpgsqlDbContext<AppDbContext>("mydb");Each component wires up health checks, telemetry, and retry policies for that specific service.
The Dev Dashboard
When you run the AppHost, a local dashboard opens at http://localhost:15888:
Dashboard shows:
⢠All running resources (services, containers, databases)
⢠Structured logs from every service in one view
⢠Distributed traces ā see a request as it flows through multiple services
⢠Metrics ā CPU, memory, request rate, error rate
⢠Environment variables and connection strings for each serviceThis is the same observability you'd have in production ā available on day one of local development.
Deploying with Aspire
# Deploy to Azure Container Apps (ACA)
dotnet tool install -g aspire.cli
aspire deployAspire generates the Azure Container Apps YAML and deploys all services, automatically provisioning managed Redis (Azure Cache for Redis) and PostgreSQL (Azure Database for PostgreSQL) to replace the local Docker containers.
Key Takeaways
- App Host is the single source of truth for your distributed app ā services, databases, and their connections
- Service Defaults gives every service OpenTelemetry, health checks, and resilient HTTP clients in one line
- Service discovery replaces hard-coded URLs ā services find each other by name
- Aspire components are opinionated integrations that include health checks and telemetry out of the box
- The dev dashboard gives production-grade observability locally ā traces, logs, and metrics from day one
Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.