Skip to main content
This quickstart will guide you through creating, running, and exploring your first .NET Aspire application. You’ll build a simple web application with an API backend, Redis cache, and see how Aspire orchestrates everything together.

Prerequisites

Before you begin, make sure you have:
You need .NET 9.0 or later. Check your version:
dotnet --version
If you need to install or update, visit dotnet.microsoft.com/download.
Aspire uses containers for infrastructure services like databases and caches. Install one of:Verify Docker is running:
docker --version
The Aspire CLI will be installed in the first step of this quickstart.

Step 1: Install the Aspire CLI

The Aspire CLI provides commands to create, run, and manage Aspire projects.
irm https://aspire.dev/install.ps1 | iex
Verify the installation:
aspire --version
The CLI will automatically add itself to your PATH. You may need to restart your terminal for the changes to take effect.

Step 2: Create Your First Aspire App

Create a new Aspire application using the starter template:
aspire new
The CLI will ask you a few questions:
Enter the project name: my-first-app
Enter the output path: ./my-first-app
✔ Using Redis Cache for caching.
Select a template version:
  > stable
Navigate to your new project:
cd my-first-app
The aspire new command creates a solution with three projects:
  • AppHost - Orchestrates your app (defines the app model)
  • ApiService - A backend API service
  • Web - A Blazor web frontend

Step 3: Explore the Project Structure

Let’s look at what was created:
my-first-app/
├── AppHost/
│   ├── Program.cs           # App model definition
│   └── AppHost.csproj
├── ApiService/
│   ├── Program.cs           # API service
│   └── ApiService.csproj
├── Web/
│   ├── Program.cs           # Web frontend
│   ├── Components/
│   └── Web.csproj
└── my-first-app.sln

The AppHost

Open AppHost/Program.cs to see how your application is defined:
AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

var apiService = builder.AddProject<Projects.ApiService>("apiservice")
    .WithHttpHealthCheck("/health");

builder.AddProject<Projects.Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithHttpHealthCheck("/health")
    .WithReference(cache)
    .WaitFor(cache)
    .WithReference(apiService)
    .WaitFor(apiService);

builder.Build().Run();
This code:
  1. Creates a Redis cache container
  2. Adds the API service with a health check
  3. Adds the web frontend that references both the cache and API
  4. Sets up dependencies so services start in the right order

The API Service

The API service (ApiService/Program.cs) is a standard ASP.NET Core minimal API with Aspire service defaults:
ApiService/Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add service defaults (telemetry, health checks, service discovery)
builder.AddServiceDefaults();

builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();

var app = builder.Build();

app.UseExceptionHandler();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

string[] summaries = ["Freezing", "Bracing", "Chilly", "Cool", 
                      "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast");

app.MapDefaultEndpoints(); // Exposes health checks

app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

The Web Frontend

The web frontend is a Blazor application that calls the API service. Notice how it uses service discovery:
Web/Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();
builder.AddRedisOutputCache("cache");

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

// Service discovery: "apiservice" resolves to the actual URL
builder.Services.AddHttpClient<WeatherApiClient>(client =>
    {
        client.BaseAddress = new("https+http://apiservice");
    });

var app = builder.Build();

app.UseOutputCache();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

app.MapDefaultEndpoints();

app.Run();
The URL "https+http://apiservice" uses service discovery. Aspire automatically resolves “apiservice” to the correct URL, preferring HTTPS over HTTP. No hardcoded ports or hosts needed!

Step 4: Run Your Application

Start your entire distributed application with a single command:
aspire run
You’ll see output similar to:
Building...
Launching Aspire dashboard: http://localhost:15085/login?t=<token>
Starting resource cache...
Starting resource apiservice...
Starting resource webfrontend...

Aspire application is running at:
  Dashboard: http://localhost:15085
  Web:       http://localhost:5174
1

Dashboard Opens Automatically

Your browser will automatically open the Aspire Dashboard. This is your command center for monitoring the application.The dashboard shows:
  • Resources: All running services and containers
  • Console Logs: Live logs from each resource
  • Structured Logs: Searchable, filterable telemetry
  • Traces: Distributed traces across service calls
  • Metrics: Performance counters and custom metrics
2

View Running Resources

In the dashboard, click on the Resources tab. You’ll see:
  • cache (Redis container) - Running on a random port
  • apiservice (.NET project) - Your API service
  • webfrontend (.NET project) - Your web frontend
Each resource shows its status, endpoints, and environment variables.
3

Open the Web Application

Click on the endpoint for webfrontend or navigate to http://localhost:5174 (the port may vary).You’ll see a Blazor web app showing a weather forecast fetched from the API service.
4

Explore Logs and Traces

In the dashboard:
  1. Click Console Logs to see live output from all services
  2. Click Structured Logs to filter and search telemetry
  3. Click Traces to see the request flow from web → API
Make a few requests in the web app, then explore the traces to see how requests flow through your distributed application.
Notice you didn’t have to:
  • Configure connection strings
  • Set up service discovery
  • Configure telemetry or logging
  • Manage ports manually
Aspire handled all of that automatically!

Step 5: Make Changes and See Hot Reload

With your app still running, let’s make a change:
  1. Open ApiService/Program.cs
  2. Change the weather summaries:
ApiService/Program.cs
string[] summaries = ["Sunny", "Partly Cloudy", "Cloudy", "Rainy", "Stormy"];
  1. Save the file
Aspire will automatically rebuild and restart the API service. Refresh your web app to see the new weather descriptions.
Hot reload works for code changes in your services. Changes to the AppHost require restarting aspire run.

Step 6: Add a Database

Let’s add a PostgreSQL database to store weather data.
  1. Stop the app (Ctrl+C in your terminal)
  2. Open AppHost/Program.cs and add PostgreSQL:
AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");

// Add PostgreSQL with a database
var postgres = builder.AddPostgres("postgres")
    .WithPgAdmin()  // Optional: adds pgAdmin UI
    .AddDatabase("weatherdb");

var apiService = builder.AddProject<Projects.ApiService>("apiservice")
    .WithHttpHealthCheck("/health")
    .WithReference(postgres);  // Reference the database

builder.AddProject<Projects.Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithHttpHealthCheck("/health")
    .WithReference(cache)
    .WaitFor(cache)
    .WithReference(apiService)
    .WaitFor(apiService);

builder.Build().Run();
  1. Add the PostgreSQL client integration to your API service:
cd ApiService
dotnet add package Aspire.Npgsql
cd ..
  1. Update ApiService/Program.cs to use the database:
ApiService/Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

// Add PostgreSQL
builder.AddNpgsqlDataSource("weatherdb");

builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();

var app = builder.Build();

// ... rest of the code
  1. Run the app again:
aspire run
Now you’ll see a postgres container in the dashboard, and the API service has access to the database connection string automatically!

Understanding What Happened

When the web frontend references the API service with client.BaseAddress = new("https+http://apiservice"), Aspire:
  1. Resolves “apiservice” to the actual URL at runtime
  2. Handles port allocation automatically
  3. Prefers HTTPS over HTTP when available
  4. Updates the configuration if services restart on different ports
When the API service references the database with builder.AddNpgsqlDataSource("weatherdb"), Aspire:
  1. Injects the connection string as configuration
  2. Uses the name “weatherdb” to match the resource in AppHost
  3. Automatically updates if the database container restarts
The .WithReference() and .WaitFor() methods create a dependency graph:Aspire ensures resources start in the correct order and only after their dependencies are ready.
The builder.AddServiceDefaults() call adds:
  • OpenTelemetry exporters that send data to the dashboard
  • Structured logging with proper formatting
  • Distributed tracing context propagation
  • Metrics collection and export
  • Health check endpoints
All without you writing any telemetry code!

Next Steps

Core Concepts

Learn more about the app model and how resources work

Explore Integrations

Discover 40+ integrations for databases, messaging, and cloud services

Build Real Apps

Follow guides to build production-ready applications

Deploy to Production

Learn how to deploy your Aspire app to Kubernetes or Azure

Common Next Actions

Add More Services

You can add other types of resources to your AppHost:
// Add a Node.js app
builder.AddNodeApp("frontend", "../client-app", "app.ts")
    .WithHttpEndpoint(env: "PORT");

// Add a Python service
builder.AddUvicornApp("ml-service", "../python-service", "app:app")
    .WithReference(postgres);

// Add RabbitMQ
var messaging = builder.AddRabbitMQ("messaging");

Explore the Dashboard

The Aspire Dashboard is powerful. Try:
  • Filtering logs by severity or resource
  • Following a distributed trace from frontend to backend
  • Viewing metrics over time
  • Checking environment variables injected into each service

Learn the CLI

Explore other CLI commands:
aspire --help           # See all commands
aspire new --help       # Create new projects from templates
aspire add postgres     # Add an integration to your project
aspire logs apiservice  # View logs for a specific service
aspire stop             # Stop the running application

Troubleshooting

Make sure Docker or Podman is running:
docker ps
If you see an error, start Docker Desktop or Podman Desktop.
If you get a “port already in use” error, Aspire will automatically try other ports. If you need to specify a port:
builder.AddProject<Projects.Web>("webfrontend")
    .WithHttpEndpoint(port: 8080);
The dashboard URL is shown in the terminal when you run aspire run. Copy the URL (including the token) and paste it into your browser.The token is required for authentication during development.
Make sure you:
  1. Added .WithReference() in the AppHost
  2. Used the correct resource name in your service code
  3. Called builder.AddServiceDefaults() in your service
Congratulations! You’ve created, run, and explored your first .NET Aspire application. You’re now ready to build more complex distributed applications with ease.

Build docs developers (and LLMs) love