Getting Started With .NET Aspire 13: Building and Deploying an App
A beginner-friendly guide to .NET Aspire 13: build a small app with PostgreSQL and Redis, watch it run on the dashboard, then deploy with Docker Compose.
Getting Started With .NET Aspire 13: Building and Deploying an App
Imagine your mother is cooking a big family dinner. She has rice on one stove, dal on another, and sabzi in the oven. Each dish needs different heat and a different amount of time. If she had to walk to a different room for every pot, dinner would be a mess. Instead, she stands in one kitchen and watches all the pots at once. She knows which one is ready, which one needs salt, and which one is about to burn.
A modern app is a lot like that dinner. It is not just one thing. It has a web API, a database, a cache, and maybe a background worker. Each part runs on its own. Keeping them all started, connected, and healthy on your laptop can feel like running between rooms.
.NET Aspire is the single kitchen for your app. It lets you describe all your parts in one place, start them with one command, and watch them all on one screen. In this guide we will build a small app with Aspire 13, run it, look at the dashboard, and then deploy it using Docker Compose. We will use simple English and go step by step.
What is .NET Aspire, really?
.NET Aspire is a set of tools for building cloud-ready apps. "Cloud-ready" just means the app is built in a tidy way so it can run on your machine today and on a server later, without big changes.
The heart of Aspire is a special project called the AppHost. The AppHost is not your real app. It is a small C# project whose only job is to describe and start the other parts. Think of it as the recipe card that lists every pot and which pot waits for which.
Each part that Aspire manages is called a resource. A resource can be your API project, a PostgreSQL database, a Redis cache, or even a plain container. You list these resources in code, and Aspire takes care of starting them in the right order and wiring them together.
One important thing to remember: Aspire's job is to make your local development lovely. It is not a replacement for big production systems like Kubernetes. When you deploy, Aspire helps you generate the right files, but the running of production is still done by tools like Docker Compose or your cloud provider. Keep that idea in your pocket. It will save you confusion later.
What you need before you start
Here is a small checklist. Tick each box before you write any code.
| Tool | Why you need it | How to check |
|---|---|---|
| .NET 10 SDK | Aspire 13 AppHost needs it to build | dotnet --version |
| A container runtime | To run PostgreSQL and Redis | docker --version |
| The Aspire CLI | To create, run, and deploy | aspire --version |
| A code editor | To write C# (VS 2026, VS Code, Rider) | open it |
If aspire --version fails, you can install the CLI as a global .NET tool. The Aspire CLI is the friendly command-line helper that runs all the steps for you. Once these four things are ready, you are good to go.
Setup before building
Steps
SDK
Install .NET 10
Runtime
Start Docker Desktop
CLI
Install Aspire CLI
Editor
Open your editor
Step 1: Create the project
The fastest way to begin is the Aspire CLI. Open a terminal in an empty folder and run a single command.
aspire newThe CLI asks you a few simple questions. It asks what kind of starter you want and what to name it. Pick the starter template that gives you an AppHost plus a sample Web API. When it finishes, you will see a few folders. The most important one ends with .AppHost. That is the recipe card we talked about.
Inside that project there is a file called AppHost.cs. Open it. This file is where the magic lives. It looks a little scary at first, but it is just a list. Let us build it up slowly.
Step 2: Describe your app in the AppHost
Every AppHost starts the same way. You make a builder, add your resources, and then build and run.
var builder = DistributedApplication.CreateBuilder(args);
// Add a PostgreSQL database server and one database inside it
var postgres = builder.AddPostgres("postgres")
.AddDatabase("appdata");
// Add a Redis cache for fast lookups
var cache = builder.AddRedis("cache");
// Add our Web API project and connect it to both
builder.AddProject<Projects.Api>("api")
.WithReference(postgres)
.WithReference(cache)
.WaitFor(postgres)
.WaitFor(cache);
builder.Build().Run();Let us read this like a story. First we say "I want a Postgres server, and inside it a database named appdata." Then we say "I also want a Redis cache." Then we add our API project and tell Aspire that the API uses the database and the cache. That is what WithReference means. The WaitFor calls tell Aspire to wait until the database and cache are ready before starting the API, just like waiting for the water to boil before adding the rice.
The best part is what you do not see here. You did not write a connection string. You did not copy a password into a config file. Aspire creates the database, makes a connection string, and hands it to the API automatically. This is called service discovery and configuration injection. Your API just asks for "the connection named appdata" and Aspire fills in the rest.
Step 3: Use the connection in your API
On the API side, you add the matching Aspire integration packages and a line or two of setup. An integration is a small helper that knows how to talk to one kind of resource, like Postgres or Redis. It also adds health checks and telemetry for free.
var builder = WebApplication.CreateBuilder(args);
// These match the names from the AppHost
builder.AddNpgsqlDbContext<AppDbContext>("appdata");
builder.AddRedisDistributedCache("cache");
var app = builder.Build();
app.MapGet("/products", async (AppDbContext db) =>
await db.Products.ToListAsync());
app.Run();Notice the names. In the AppHost we named the database appdata and the cache cache. Here we ask for those exact names. Aspire matches them up. If you change a name in one place, change it in the other too. That is the one rule to remember.
Step 4: Run everything with one command
Now the fun part. Go back to your terminal and run:
aspire runAspire reads your AppHost, starts a Postgres container, starts a Redis container, waits for them to be healthy, and then starts your API. In one command, your whole "dinner" is cooking. You did not run three separate terminals. You did not start Docker by hand.
What aspire run does
Steps
Read AppHost
Load the recipe
Start DB
Boot Postgres
Start Cache
Boot Redis
Start API
Wait, then run
Open Dashboard
Show the screen
Step 5: Meet the Aspire Dashboard
When the app starts, Aspire opens a web page called the dashboard. This is your single kitchen window. On it you can see every resource, whether it is green (healthy) or red (broken), and a button to open each one.
The dashboard has four very useful views:
| View | What it shows you |
|---|---|
| Resources | Every part, its state, and its URL |
| Logs | The text each part prints out |
| Traces | The full path of one request across parts |
| Metrics | Numbers like request count and memory |
The Traces view is the one that feels like magic. When a request comes into your API, goes to Redis, then to Postgres, and back, the dashboard draws that whole journey as one timeline. You can see exactly which step was slow. This works because Aspire turns on OpenTelemetry for you. OpenTelemetry is a common language that apps use to report what they are doing, so all your parts can be watched in one place.
// Aspire's shared "ServiceDefaults" project turns this on for every service.
// You usually just call one line in each app:
builder.AddServiceDefaults();
// It wires up logging, metrics, traces, and health checks together.Spend a few minutes clicking around the dashboard. Send a request to your API and watch the trace appear. This single screen is one of the biggest reasons people love Aspire.
Step 6: Deploy with Docker Compose
Running on your laptop is great, but the goal is to share your app. Aspire 13 makes the first step of deployment friendly. We will use Docker Compose, which is a simple way to run several containers together on one machine or server.
First, add the Docker Compose support to your project with the CLI.
aspire add dockerThen tell your AppHost that you want a Docker Compose environment. This is one new line near the top of AppHost.cs.
var builder = DistributedApplication.CreateBuilder(args);
// Tell Aspire we want to target Docker Compose when we deploy
builder.AddDockerComposeEnvironment("env");
var postgres = builder.AddPostgres("postgres").AddDatabase("appdata");
var cache = builder.AddRedis("cache");
builder.AddProject<Projects.Api>("api")
.WithReference(postgres)
.WithReference(cache)
.WithExternalHttpEndpoints() // make the API reachable from outside
.WaitFor(postgres)
.WaitFor(cache);
builder.Build().Run();The line WithExternalHttpEndpoints() is important for deployment. It tells Aspire "this API should be reachable from the outside world," not just from other containers. Without it, your API would be hidden.
Now deploy with one command:
aspire deployThis single command does a lot. It builds a container image for your API, writes the Docker Compose YAML file for you, and starts everything. You did not hand-write any YAML. When it finishes, the output shows you the local URLs where your services are running.
When you are done testing and want to remove everything cleanly, there is a matching command:
aspire destroyThis tears down what you deployed so nothing keeps running and nothing keeps costing money. It is a good habit to clean up after every practice session.
A quick note on Azure (when you grow)
Docker Compose is perfect for learning and for small servers. Later, when you want a real cloud home, Aspire can target Azure Container Apps instead. The pattern is almost the same: you add the Azure package and swap one line in the AppHost.
aspire add azure-appcontainers// Instead of Docker Compose, use Azure Container Apps
builder.AddAzureContainerAppEnvironment("env");Then aspire deploy builds your images, pushes them to Azure, and creates the cloud resources using Bicep files that Aspire writes for you. The lovely thing is that the rest of your AppHost stays the same. You learned one model, and it carries you from laptop to cloud.
A word on libraries and licensing
If you read older tutorials, you may see message libraries like MediatR and MassTransit used inside Aspire apps. Be careful here. As of now, both MediatR and MassTransit have moved to a commercial license for many uses. They are still good tools, but you should check their current license and pricing before you put them in a real product. For learning Aspire, you do not need them at all. A plain Web API with a database and a cache, like the one we built, is enough.
Also good to know: .NET 10 is the current LTS (long-term support) release, C# 14 has shipped, and C# 15 with union types is in early .NET 11 previews. For this guide, stick with .NET 10. It is stable and supported for a long time.
Common beginner mistakes (and easy fixes)
Here are a few bumps new learners hit. None of them are scary once you know them.
| Problem | Likely cause | Fix |
|---|---|---|
| Containers do not start | Docker Desktop is closed | Open Docker and try again |
| API can't find the database | Names don't match | Use the same name in AppHost and API |
| API starts before DB is ready | Missing WaitFor | Add .WaitFor(postgres) |
| Can't reach API after deploy | No external endpoint | Add .WithExternalHttpEndpoints() |
If something breaks, open the dashboard first. The red resource and its logs almost always tell you what went wrong. Reading logs is a skill, and the dashboard makes it gentle.
Why this matters
Before Aspire, a beginner had to learn many tools at once just to run a small app: Docker commands, connection strings, environment variables, and a separate tool for logs. That is a lot of homework before you write a single feature. Aspire moves that homework into one tidy C# file and one dashboard. You spend your energy on your app, not on plumbing. And because the same model works for deployment, the step from "runs on my laptop" to "runs on a server" becomes small and calm instead of large and scary.
Quick recap
- .NET Aspire is like a single kitchen that starts and watches every part of your app.
- The AppHost is a small C# project that lists your resources, such as a Web API, PostgreSQL, and Redis.
WithReferenceconnects parts; Aspire creates connection strings for you, so you write no secrets by hand.aspire runstarts everything with one command and opens the dashboard.- The dashboard shows resources, logs, traces, and metrics, powered by OpenTelemetry.
aspire add dockerplusAddDockerComposeEnvironmentplusaspire deployships your app with Docker Compose, no hand-written YAML.- The same model targets Azure Container Apps later by swapping one line.
- Use
aspire destroyto clean up, and check the license of MediatR/MassTransit before using them in real products. - Stick with .NET 10 LTS for a stable, well-supported base.
References and further reading
- Aspire AppHost overview (official docs)
- Deploy your first Aspire app (official docs)
- Aspire prerequisites and tooling (official docs)
- .NET Aspire orchestration overview (Microsoft Learn)
- .NET Aspire 13.2 release notes (InfoQ)
Related Posts
Using .NET Aspire With the Docker Publisher: A Beginner Guide
Learn how to turn a .NET Aspire app into a ready-to-run docker-compose.yaml with one command using the Docker publisher. Simple, step-by-step guide.
.NET Aspire: A Game Changer for Cloud-Native Development
A beginner-friendly guide to .NET Aspire, the cloud-native stack that orchestrates your services, databases, and dashboards with one simple command.
How To Deploy a .NET App to Azure Using Neon Postgres and .NET Aspire
A beginner-friendly, step-by-step guide to deploying a .NET 10 web API to Azure Container Apps with a free Neon serverless Postgres database and .NET Aspire.
How .NET Aspire Simplifies Service Discovery for Your Apps
Learn how .NET Aspire service discovery lets your services find each other by name, with no hardcoded URLs, ports, or environment headaches.
Containerize Your .NET Applications Without a Dockerfile
Learn how to build container images for your .NET apps using the SDK and dotnet publish, with no Dockerfile needed. Beginner-friendly guide for .NET 10.
How to Build a CI/CD Pipeline With GitHub Actions and .NET
A beginner-friendly guide to building a CI/CD pipeline for .NET with GitHub Actions: build, test, cache, publish, and deploy your app automatically.