Dapr keeps infrastructure concerns out of your application code. Aspire keeps local orchestration out of your head. Put them together and you get one of the smoothest .NET development loops available today.
This bonus post is optional and .NET‑specific, but if you’re a .NET engineer, it’s worth your time. It shows how Aspire and Dapr complement each other, how they fit into a clean local development workflow, and how to wire them together in a real project.
This bonus post uses .NET Aspire 13.1 and Dapr 1.16, the current stable versions at the time of writing. Aspire 13.1 provides the new distributed application model, automatic dashboard integration, and first‑class Dapr sidecar orchestration. Dapr 1.16 provides the building blocks (state, pub/sub, bindings, secrets, observability) used throughout the examples in this repository, including the code to demonstrate running with Aspire.
How Aspire and Dapr Work Together
What Each Provides
Dapr provides infrastructure building blocks:
- State management
- Pub/sub
- Bindings
- Secrets
- Observability
- Service invocation
Aspire provides local application orchestration:
- Service discovery
- Configuration
- Containerized dependencies
- A unified dashboard
- A single command to run your entire app
Once you understand what each tool provides individually, the next step is seeing how they work together in a real application.
How They Fit Together
Aspire defines your application topology.
Dapr injects infrastructure capabilities into each service.
The workflow looks like this:
- Aspire AppHost defines your services.
- Dapr sidecars run next to each service.
- Dapr components are loaded automatically by each sidecar when
ResourcesPathsis configured. - Your services use the Dapr client without caring about ports or infrastructure.
This results in a clean, local environment without the usual orchestration overhead.
Together, Aspire and Dapr give you a unified way to run multiple services, sidecars, and infrastructure components with minimal configuration.
Now that we’ve covered how Aspire and Dapr complement each other conceptually, let’s look at a minimal example that wires them together in a real project.
A Minimal Aspire + Dapr Example
Folder structure
src/
orderservice-dotnet/
inventoryservice-dotnet/
aspirehost/
components/
The components/ folder contains standard Dapr component YAML files (state store, pub/sub, etc.). Aspire mounts this folder automatically so the sidecars can load them. These YAML files match the Dapr building block examples used throughout the repository, so the same components work whether you run via Aspire or the Dapr CLI.
Step 1: Add the Dapr hosting package
In your AppHost project:
dotnet add package CommunityToolkit.Aspire.Hosting.Dapr
Step 2: Define your services with Dapr sidecars
Aspire generates strongly typed project references under the Projects namespace (e.g., Projects.orderservice_dotnet). These types are created automatically when the AppHost and services are part of the same solution.
With the project structure in place, the AppHost simply wires each service to a Dapr sidecar and mounts the shared components folder.
AppHost.cs:
using CommunityToolkit.Aspire.Hosting.Dapr;
var builder = DistributedApplication.CreateBuilder(args);
builder.AddProject<Projects.orderservice_dotnet>("ordersservice")
.WithDaprSidecar(new DaprSidecarOptions
{
AppId = "orderservice",
ResourcesPaths = [Path.Combine("../..", "components")]
});
builder.AddProject<Projects.inventoryservice_dotnet>("inventoryservice")
.WithDaprSidecar(new DaprSidecarOptions
{
AppId = "inventoryservice",
ResourcesPaths = [Path.Combine("../..", "components")]
});
builder.Build().Run();
What this gives you:
- Aspire launches all services defined in the AppHost
- Aspire launches the Dapr sidecars that are configured using
.WithDaprSidecar() - Dapr components are loaded automatically by each sidecar based on the configured
ResourcesPaths. - Everything appears in the Aspire dashboard
No manual dapr run commands.
No launch profiles.
No need to manually assign ports.
Observability Across Both Worlds
Aspire 13.1 automatically configures OTLP endpoints and dashboard settings, so no manual environment variables are required.
The Aspire dashboard surfaces both application‑level and infrastructure‑level signals, giving you a unified view of the entire local environment.
You get two layers of visibility:
Aspire dashboard
- Running services
- Sidecars
- Logs
- Environment variables
- Health checks
Dapr observability
- Traces
- Metrics
- Component logs
Together, they give you a complete picture of both application and infrastructure behaviour.
When Aspire + Dapr Is a Great Fit
- .NET microservices
- Local-first development workflows
- Teams who want a clean, discoverable environment
- Developers who want to avoid docker-compose sprawl
- Systems where infrastructure concerns must stay out of app code
When it’s not ideal
- Polyglot systems
- Environments where Aspire isn’t available
- Teams needing full control over orchestration
Aspire can orchestrate non‑.NET services, but they won’t appear in the dashboard with the same depth of metadata, and Aspire cannot generate strongly typed project references for them.
Common Pitfalls (and How to Avoid Them)
- Don’t mix Aspire service discovery with Dapr service invocation.
They solve different problems. - Keep ports consistent when needed.
Both Aspire and Dapr assign dynamic ports by default. If your services rely on fixed ports, you’ll need to specify them explicitly. - Most Dapr components don’t hot-reload.
Restarting the AppHost when changing YAML ensures changes are picked up.
Final Thoughts
Aspire 13.1 and Dapr 1.16 work together cleanly: Aspire handles orchestration and developer experience, while Dapr provides infrastructure building blocks. Used together, they give you a fast, modern, production‑aligned development loop with almost no ceremony.