Add Aspire to the app you already have instead of rebuilding your solution around a new template. Start by choosing the AppHost style that fits your repo, then register the services, containers, shared infrastructure, and, when needed, custom executables you already run today, regardless of whether those workloads are written in C#, Node.js, Python, Go, Rust, Java, or something else.
As distributed applications grow, local development often turns into a collection of fragile scripts, copied connection strings, and startup-order tribal knowledge. Aspire gives you a single orchestration layer for the resources you already own. Define the relationships once in code, and Aspire handles service discovery, configuration injection, startup ordering, and dashboard visibility.
You can also adopt Aspire incrementally. Start by modeling the parts that are hardest to keep aligned by hand, such as containers, databases, caches, queues, background workers, and local dev commands. Add telemetry when you’re ready, then deepen the model as your app grows.
This guide is organized around the kinds of resources you already manage rather than around a preferred service language. Aspire is multi-language by design, so one AppHost can orchestrate a system that spans C#, Node.js, Python, Go, Rust, Java, and other supported workloads.
Existing services with hosting integrations: You already have C# services, Node.js apps, Vite frontends, Python apps, or ASGI apps such as FastAPI and want to use Aspire’s dedicated hosting APIs.
Existing containers and shared infrastructure: You already have images, Docker Compose files, databases, caches, queues, or reverse proxies that you want Aspire to coordinate.
Existing C# services: You already have C# projects or file-based C# apps and want the C# AppHost to orchestrate them directly.
In every scenario, you can choose either AppHost style and mix resource types in the same application model.
When a dedicated hosting API exists for a workload, prefer it over AddExecutable or addExecutable. Executable resources are the fallback for custom tools, one-off commands, or workloads that do not yet have a dedicated hosting integration.
Use a C# AppHost when your repo already centers on C# or when you want a single-file orchestrator that still fits naturally into .NET SDK and IDE workflows.
Lives in a single apphost.cs file that uses #:sdk and #:package directives
Common APIs include:
API
Description
AddContainer()
Run a prebuilt container image that already exists in your current workflow.
AddCSharpApp()
Point a file-based AppHost at an existing C# app or .csproj without creating a separate AppHost project graph.
AddDockerfile()
Build and run a container from an existing Dockerfile in your repo.
AddExecutable()
Fall back to a custom command when a dedicated hosting API does not exist yet.
AddJavaScriptApp(), AddNodeApp(), AddViteApp()
Model JavaScript and TypeScript workloads, from general package-script apps to Node entrypoints and Vite frontends.
AddParameter()
Define reusable config values and secrets for the resources in your model.
AddPostgres(), AddRedis()
Add shared infrastructure with first-class integrations and connection wiring.
AddPythonApp(), AddUvicornApp()
Model Python scripts, workers, and ASGI apps such as FastAPI.
WaitFor(), WithHttpEndpoint(), WithReference()
Wire service discovery, startup ordering, and HTTP endpoints between resources.
Fits naturally into existing .NET SDK, IDE, and repo workflows
Use a TypeScript AppHost when your repo already centers on a Node.js workspace or when you prefer path-based orchestration in TypeScript.
Lives in apphost.ts
Common APIs include:
API
Description
addContainer()
Run a prebuilt container image that you already publish or pull today.
addCSharpApp()
Point at an existing C# app, .csproj, or directory directly from a TypeScript AppHost without relying only on addProject().
addDockerfile()
Build and run a container directly from a Dockerfile in the repo.
addExecutable()
Fall back to a custom command for unsupported runtimes or one-off tools.
addNodeApp(), addViteApp()
Model Node.js services and Vite frontends with JavaScript-aware defaults.
addParameter()
Define reusable config values and secrets that multiple resources can consume.
addPostgres(), addRedis()
Add shared infrastructure with first-class integrations and references.
addProject()
Add an existing project by path, such as a .csproj, into a TypeScript AppHost.
addPythonApp(), addUvicornApp()
Model Python scripts, workers, and ASGI apps such as FastAPI.
waitFor(), withHttpEndpoint(), withReference()
Wire service discovery, startup ordering, and HTTP endpoints between resources.
Fits naturally into existing package-manager and monorepo workflows
The command runs in interactive mode by default. It can detect existing C# projects, create a single-file AppHost, and add the initial package directives and configuration it needs.
After initialization, a typical C#-centric repo might look like this:
apphost.cs(new)
apphost.run.json(new)
Directoryservices/
DirectoryApi/
ExampleEcommerce.Api.csproj
DirectoryWeb/
package.json
Directorysrc/
…
Directoryworkers/
Directoryinventory-sync/
worker.py
Starter AppHost:
apphost.cs — Initial state
#:sdk Aspire.AppHost.Sdk@13.2.0
var builder =DistributedApplication.CreateBuilder(args);
// TODO: Add resources here
builder.Build().Run();
Add #:package directives in apphost.cs for the hosting integrations you use, such as Aspire.Hosting.Redis, Aspire.Hosting.Python, Aspire.Hosting.JavaScript, and Aspire.Hosting.PostgreSQL.
Navigate to the root of your existing workspace or repo:
Navigate to your workspace or repo
cd/path/to/your-workspace
Run aspire init with the TypeScript AppHost option:
Initialize Aspire with a TypeScript AppHost
aspireinit--languagetypescript
If you omit --language typescript, choose TypeScript when the CLI prompts for the AppHost language.
Once you have an AppHost, use it to model the parts of your system that matter during local development: workloads, supporting infrastructure, and the connections between them. A resource does not need to mirror every repo boundary or implementation detail; it should represent something Aspire needs to start, observe, or connect.
Think first about relationships: which workloads consume which backing services, which endpoints need to be reachable, and which resources must be ready before others can do useful work.
The same patterns apply across AppHost styles:
Use WithReference or withReference to express that one resource depends on another and to flow connection information through the model.
Use WaitFor or waitFor when readiness matters and one resource should not start until another is available.
Scenario: Existing services with hosting integrations
Use this approach when Aspire already has a first-class resource type for the workload you want to run. That keeps the application model focused on what the service is and what it depends on, instead of reducing it to a generic shell command.
Common examples include Node.js apps, Vite frontends, Python workers, and Uvicorn-based APIs.
If a workload does not have a dedicated hosting API yet, model it as an executable resource with AddExecutable or addExecutable so it can still participate in the same application model.
Use this approach when the important boundary is the runtime environment itself: a published container image, a shared database, a cache, a queue, or an existing infrastructure topology. Model the shared resources first, then attach the workloads that consume them so connectivity, configuration, and startup order are explicit.
When Aspire has a first-class integration for that infrastructure, add it first:
Use this approach when your repo already contains .NET services that should stay where they are. The goal is to register those services as resources by pointing at their existing paths, then connect the infrastructure, endpoints, and health checks they already need as part of the larger application model.
In a file-based C# AppHost, AddCSharpApp is the direct way to point at an existing C# service path. This works with single-file C# apps, directories, or existing .csproj files.
Use this scenario when Docker Compose already captures the shape of your system. Treat the Compose file as a map of workloads, shared infrastructure, exposed ports, and dependency edges that you want to restate in the AppHost.
The goal is not a line-by-line translation of every field, but a clearer resource model of the same relationships.
These scenarios are starting points, not mutually exclusive modes. Most real apps mix workload-specific resources, containers, shared infrastructure, project-path references, and occasional custom commands in a single application model. The key is that dependencies, endpoints, configuration, and startup behavior become explicit.
Telemetry is configured inside the workloads that emit it, not in the AppHost itself. Aspire gives those workloads an OTLP destination and a shared dashboard during local orchestration, but each service still uses the observability libraries that fit its runtime.
For other runtimes, use the OpenTelemetry SDK or instrumentation library that matches the runtime you are already using, then export telemetry to the OTLP endpoint Aspire provides during local orchestration.
At this point, you have the core workflow: describe the resources your app needs, connect the workloads that depend on them, and let Aspire run the system together during local development. From there, you can deepen the setup incrementally instead of trying to remodel the entire app at once.
Learn more about Executable resources for custom commands and non-project workloads