Add Aspire to an existing app
Add Aspire to the app you already have instead of rebuilding your solution around a new template. The fastest path is aspire init paired with an AI coding agent that automatically discovers your services and wires them into an AppHost. If you prefer full control, manual steps are provided below.
Why add Aspire to an existing app?
Section titled “Why add Aspire to an existing app?”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.
Prerequisites
Section titled “Prerequisites”Before you begin, make sure you have:
- Aspire CLI installed
- An existing application or workspace to add Aspire to
- The runtimes and tools your existing services already need
AppHost-specific requirements
Section titled “AppHost-specific requirements”- .NET SDK 10.0 or later
- Visual Studio 2022 17.13 or later, Visual Studio Code, or JetBrains Rider (optional)
- Node.js 22 or later
- npm, yarn, or pnpm
Recommended: Use an AI coding agent with the “aspireify” skill
Section titled “Recommended: Use an AI coding agent with the “aspireify” skill”The fastest way to add Aspire to an existing app is to let aspire init scaffold the skeleton, then hand off wiring to the aspireify agent skill. The skill handles resource discovery, dependency wiring, OpenTelemetry setup, and validation automatically.
-
Run
aspire initin your repo root:Initialize Aspire aspire initChoose your AppHost language (C# or TypeScript) when prompted, or pass
--language csharp/--language typescript. The command creates a minimal AppHost file, anaspire.config.json, and installs theaspireifyskill into your agent’s skill directory. -
Ask your AI coding agent to run the
aspireifyskill. The agent will:- Scan your repo and discover existing projects, services, containers, and infrastructure
- Ask you to confirm the resources it found, which ones you want included, and other clarifying questions before starting
- Wire resources into the AppHost with
WithReference,WaitFor, endpoints, and volumes - Add ServiceDefaults and configure OpenTelemetry for each service
- Validate the setup by running
aspire start
-
Once the agent reports success, run
aspire startyourself and open the dashboard to verify everything looks correct. Something not right? Tell the agent-it has plenty of tools from Aspire to troubleshoot!
For more details on the aspire init command and the aspireify skill, see the CLI reference: aspire init.
Wire your AppHost manually
Section titled “Wire your AppHost manually”If you prefer full control over the wiring, or want to understand what the aspireify skill does under the hood, follow the manual steps below. This is also the reference for anyone extending or customizing an AppHost after the initial setup.
Choose your AppHost
Section titled “Choose your AppHost”The AppHost is the orchestration layer. Your choice here changes how you express orchestration, not what Aspire can orchestrate.
Aspire offers two C# AppHost styles:
File-based AppHost — a single apphost.cs file that uses #:sdk and #:package directives. No .csproj, no solution integration required. Best for polyglot repos or quick setups.
Project-based AppHost — a traditional AppHost.csproj that lives inside a .sln alongside your other C# projects. Uses ProjectReference items and the generated Projects namespace for strongly-typed AddProject<T>() calls. Best when your repo is already a .NET solution and you want IDE-integrated orchestration.
Both styles use the same Aspire.AppHost.Sdk and the same hosting APIs.
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 - Runs under popular package managers including npm, pnpm, yarn, and Bun
- Fits naturally into existing package-manager and monorepo workflows
Set up your AppHost
Section titled “Set up your AppHost”File-based AppHost (default)
Section titled “File-based AppHost (default)”Use a file-based AppHost when you want a lightweight single-file orchestrator without adding a project to your solution. This is the default style created by aspire init when no .sln is detected.
-
Run
aspire initfrom your repo root. Without a.slnpresent, it creates a file-basedapphost.cs:Initialize Aspire with a file-based AppHost aspire init -
Add hosting integrations:
Add hosting integrations aspire add redis -
Wire the resources in
apphost.cs:apphost.cs #:sdk Aspire.AppHost.Sdk@13.2.0#:package Aspire.Hosting.Redis@13.2.0#pragma warning disable ASPIRECSHARPAPPS001var builder = DistributedApplication.CreateBuilder(args);var cache = builder.AddRedis("cache");var api = builder.AddCSharpApp("api", "./src/Api/MyApp.Api.csproj").WithReference(cache).WithHttpHealthCheck("/health");var worker = builder.AddCSharpApp("worker", "./src/Worker/MyApp.Worker.csproj").WithReference(cache);builder.Build().Run();
After setup, a typical repo layout looks like this:
- apphost.cs (new)
- aspire.config.json (new)
Directorysrc/
DirectoryApi/
- MyApp.Api.csproj
DirectoryWorker/
- MyApp.Worker.csproj
Project-based AppHost (with a .sln)
Section titled “Project-based AppHost (with a .sln)”Use this approach when your repo is already a .NET solution (.sln or .slnx) with multiple projects. The project-based AppHost uses ProjectReference items and the generated Projects namespace for strongly-typed AddProject<T>() calls, giving you full IDE support including IntelliSense, refactoring, and build-order awareness.
-
Run
aspire initfrom your solution root. It detects the.slnand creates a project-based AppHost automatically:Initialize Aspire in a .NET solution aspire init -
Add project references from the AppHost to each service you want to orchestrate:
Add project references dotnet add MyApp.AppHost reference src/Api/MyApp.Api.csprojdotnet add MyApp.AppHost reference src/Web/MyApp.Web.csprojdotnet add MyApp.AppHost reference src/Worker/MyApp.Worker.csproj -
Add hosting integrations:
Add hosting integrations aspire add redisaspire add postgres -
Wire the resources in the AppHost’s
Program.cs:MyApp.AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args);var cache = builder.AddRedis("cache").WithLifetime(ContainerLifetime.Persistent);var db = builder.AddPostgres("postgres").WithLifetime(ContainerLifetime.Persistent).AddDatabase("mydb");var api = builder.AddProject<Projects.MyApp_Api>("api").WithReference(db).WithReference(cache).WaitFor(db);builder.AddProject<Projects.MyApp_Web>("web").WithReference(api).WaitFor(api);builder.AddProject<Projects.MyApp_Worker>("worker").WithReference(cache).WithReference(db);builder.Build().Run();
After setup, a typical solution layout looks like this:
- MyApp.sln
DirectoryMyApp.AppHost/
- MyApp.AppHost.csproj
- Program.cs
DirectoryMyApp.ServiceDefaults/
- MyApp.ServiceDefaults.csproj
- Extensions.cs
Directorysrc/
DirectoryApi/
- MyApp.Api.csproj
DirectoryWeb/
- MyApp.Web.csproj
DirectoryWorker/
- MyApp.Worker.csproj
For the full AddProject workflow including custom type names, multi-project solutions, and launch profiles, see Project resources.
-
Run
aspire initfrom your workspace root with the TypeScript language option:Initialize Aspire with a TypeScript AppHost aspire init --language typescript -
Add hosting integrations:
Add hosting integrations aspire add redisaspire add postgres -
Wire the resources in
apphost.ts:apphost.ts import {createBuilder } from './.modules/aspire.js';function createBuilder(): IDistributedApplicationBuilderCreates a new distributed application builder
constbuilder = awaitconst builder: IDistributedApplicationBuildercreateBuilder();function createBuilder(): IDistributedApplicationBuilderCreates a new distributed application builder
constcache = awaitconst cache: RedisResourcebuilder.const builder: IDistributedApplicationBuilderaddRedis('cache');IDistributedApplicationBuilder.addRedis(name: string, options?: {port?: number;password?: string | ParameterResource;}): RedisResource (+1 overload)Adds a Redis container resource
constdb = (awaitconst db: PostgresDatabaseResourcebuilder.const builder: IDistributedApplicationBuilderaddPostgres('postgres')).IDistributedApplicationBuilder.addPostgres(name: string, options?: {userName?: string | ParameterResource;password?: string | ParameterResource;port?: number;}): PostgresServerResource (+1 overload)Adds a PostgreSQL server resource
addDatabase('mydb');PostgresServerResource.addDatabase(name: string, options?: {databaseName?: string;}): PostgresDatabaseResource (+1 overload)Adds a PostgreSQL database
constapi = awaitconst api: ProjectResourcebuilderconst builder: IDistributedApplicationBuilder.addProject('api', './src/Api/MyApp.Api.csproj')IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {launchProfileOrOptions?: ProjectResourceOptions;}): ProjectResource (+1 overload)Adds a .NET project resource
.withReference(ProjectResource.withReference(source: EndpointReference | string | uri, options?: {connectionName?: string;optional?: boolean;name?: string;} | undefined): ProjectResource (+2 overloads)Adds a reference to another resource
db)const db: PostgresDatabaseResource.withReference(ProjectResource.withReference(source: EndpointReference | string | uri, options?: {connectionName?: string;optional?: boolean;name?: string;} | undefined): ProjectResource (+2 overloads)Adds a reference to another resource
cache)const cache: RedisResource.waitFor(ProjectResource.waitFor(dependency: IResource, waitBehavior?: WaitBehavior): ProjectResourceWaits for another resource to be ready
db);const db: PostgresDatabaseResourceawaitbuilderconst builder: IDistributedApplicationBuilder.addViteApp('web', './services/web')IDistributedApplicationBuilder.addViteApp(name: string, appDirectory: string, options?: {runScriptName?: string;}): ViteAppResource (+1 overload)Adds a Vite application resource
.withReference(ExecutableResource.withReference(source: EndpointReference | string | uri, options?: {connectionName?: string;optional?: boolean;name?: string;} | undefined): ViteAppResource (+2 overloads)Adds a reference to another resource
api)const api: ProjectResource.waitFor(ExecutableResource.waitFor(dependency: IResource, waitBehavior?: WaitBehavior): ViteAppResourceWaits for another resource to be ready
api);const api: ProjectResourceawaitbuilder.const builder: IDistributedApplicationBuilderbuild().IDistributedApplicationBuilder.build(): DistributedApplicationBuilds the distributed application
run();DistributedApplication.run(cancellationToken?: cancellationToken): voidRuns the distributed application
After setup, a typical workspace layout looks like this:
- apphost.ts (new)
Directory.modules/ (new)
- …
- aspire.config.json (new)
- package.json (new or updated)
Directoryservices/
Directoryweb/
- package.json
Directorysrc/
- …
Directorysrc/
DirectoryApi/
- MyApp.Api.csproj
Scenario: Existing services with hosting integrations
Section titled “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.
#:sdk Aspire.AppHost.Sdk@13.3.0#:package Aspire.Hosting.Redis@13.3.0#:package Aspire.Hosting.Python@13.3.0#:package Aspire.Hosting.JavaScript@13.3.0
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
var api = builder.AddUvicornApp("api", "../services/api", "main:app") .WithUv() .WithReference(cache) .WithExternalHttpEndpoints();
var worker = builder.AddPythonApp("worker", "../workers/inventory-sync", "worker.py") .WithReference(cache);
var web = builder.AddViteApp("web", "../services/web") .WithReference(api) .WaitFor(api);
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const cache: RedisResource
cache = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addRedis(name: string, options?: { port?: number; password?: string | ParameterResource;}): RedisResource (+1 overload)
Adds a Redis container resource
addRedis('cache');
const const api: UvicornAppResource
api = await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addUvicornApp(name: string, appDirectory: string, app: string): UvicornAppResource
Adds a Uvicorn-based Python application resource
addUvicornApp('api', './services/api', 'main:app') .UvicornAppResource.withUv(options?: { install?: boolean; args?: string[];} | undefined): UvicornAppResource (+1 overload)
Configures uv package management for a Python application
withUv() .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): UvicornAppResource (+2 overloads)
Adds a reference to another resource
withReference(const cache: RedisResource
cache) .ExecutableResource.withExternalHttpEndpoints(): UvicornAppResource
Makes HTTP endpoints externally accessible
withExternalHttpEndpoints();
await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addPythonApp(name: string, appDirectory: string, scriptPath: string): PythonAppResource
Adds a Python script application resource
addPythonApp('worker', './workers/inventory-sync', 'worker.py') .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): PythonAppResource (+2 overloads)
Adds a reference to another resource
withReference(const cache: RedisResource
cache);
await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addViteApp(name: string, appDirectory: string, options?: { runScriptName?: string;}): ViteAppResource (+1 overload)
Adds a Vite application resource
addViteApp('web', './services/web') .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ViteAppResource (+2 overloads)
Adds a reference to another resource
withReference(const api: UvicornAppResource
api) .ExecutableResource.waitFor(dependency: IResource, waitBehavior?: WaitBehavior): ViteAppResource
Waits for another resource to be ready
waitFor(const api: UvicornAppResource
api);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();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.
For first-class workload guidance, see JavaScript integration, Python integration, and Multi-language architecture.
Scenario: Existing containers and shared infrastructure
Section titled “Scenario: Existing containers and shared infrastructure”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:
aspire add postgresaspire add redis#:sdk Aspire.AppHost.Sdk@13.3.0#:package Aspire.Hosting.PostgreSQL@13.3.0#:package Aspire.Hosting.Redis@13.3.0
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("postgres") .AddDatabase("orders");
var cache = builder.AddRedis("cache");
var api = builder.AddContainer("api", "ghcr.io/contoso/orders-api:latest") .WithReference(db) .WithReference(cache) .WithHttpEndpoint(port: 8080, targetPort: 8080, name: "http");
var web = builder.AddContainer("web", "ghcr.io/contoso/orders-web:latest") .WithReference(api) .WithHttpEndpoint(port: 3000, targetPort: 3000, name: "http");
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const db: PostgresDatabaseResource
db = (await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addPostgres(name: string, options?: { userName?: string | ParameterResource; password?: string | ParameterResource; port?: number;}): PostgresServerResource (+1 overload)
Adds a PostgreSQL server resource
addPostgres('postgres')).PostgresServerResource.addDatabase(name: string, options?: { databaseName?: string;}): PostgresDatabaseResource (+1 overload)
Adds a PostgreSQL database
addDatabase('orders');
const const cache: RedisResource
cache = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addRedis(name: string, options?: { port?: number; password?: string | ParameterResource;}): RedisResource (+1 overload)
Adds a Redis container resource
addRedis('cache');
const const api: ContainerResource
api = await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addContainer(name: string, image: AddContainerOptions): ContainerResource
Adds a container resource
addContainer('api', { AddContainerOptions.image: string
image: 'ghcr.io/contoso/orders-api', AddContainerOptions.tag: string
tag: 'latest' }) .ContainerResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ContainerResource (+2 overloads)
Adds a reference to another resource
withReference(const db: PostgresDatabaseResource
db) .ContainerResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ContainerResource (+2 overloads)
Adds a reference to another resource
withReference(const cache: RedisResource
cache) .ContainerResource.withHttpEndpoint(options?: { port?: number; targetPort?: number; name?: string; env?: string; isProxied?: boolean;} | undefined): ContainerResource (+1 overload)
Adds an HTTP endpoint
withHttpEndpoint({ port?: number | undefined
port: 8080, targetPort?: number | undefined
targetPort: 8080, name?: string | undefined
name: 'http' });
await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addContainer(name: string, image: AddContainerOptions): ContainerResource
Adds a container resource
addContainer('web', { AddContainerOptions.image: string
image: 'ghcr.io/contoso/orders-web', AddContainerOptions.tag: string
tag: 'latest' }) .ContainerResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ContainerResource (+2 overloads)
Adds a reference to another resource
withReference(const api: ContainerResource
api) .ContainerResource.withHttpEndpoint(options?: { port?: number; targetPort?: number; name?: string; env?: string; isProxied?: boolean;} | undefined): ContainerResource (+1 overload)
Adds an HTTP endpoint
withHttpEndpoint({ port?: number | undefined
port: 3000, targetPort?: number | undefined
targetPort: 3000, name?: string | undefined
name: 'http' });
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Scenario: Docker Compose
Section titled “Scenario: Docker Compose”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.
services: postgres: image: postgres:latest environment: - POSTGRES_PASSWORD=postgres - POSTGRES_DB=mydb ports: - "5432:5432"
api: build: ./api environment: - DATABASE_URL=postgres://postgres:postgres@postgres:5432/mydb depends_on: - postgres
web: build: ./web environment: - API_URL=http://api:8080 depends_on: - api#:sdk Aspire.AppHost.Sdk@13.3.0#:package Aspire.Hosting.PostgreSQL@13.3.0
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("postgres") .AddDatabase("mydb");
var api = builder.AddDockerfile("api", "./api") .WithReference(db) .WithHttpEndpoint(port: 8080, targetPort: 8080, name: "http");
var web = builder.AddDockerfile("web", "./web") .WithReference(api) .WithHttpEndpoint(port: 3000, targetPort: 3000, name: "http");
builder.Build().Run();import { function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder } from './.modules/aspire.js';
const const builder: IDistributedApplicationBuilder
builder = await function createBuilder(): IDistributedApplicationBuilder
Creates a new distributed application builder
createBuilder();
const const db: PostgresDatabaseResource
db = (await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addPostgres(name: string, options?: { userName?: string | ParameterResource; password?: string | ParameterResource; port?: number;}): PostgresServerResource (+1 overload)
Adds a PostgreSQL server resource
addPostgres('postgres')).PostgresServerResource.addDatabase(name: string, options?: { databaseName?: string;}): PostgresDatabaseResource (+1 overload)
Adds a PostgreSQL database
addDatabase('mydb');
const const api: ContainerResource
api = await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, options?: { dockerfilePath?: string; stage?: string;}): ContainerResource (+1 overload)
Adds a container resource built from a Dockerfile
addDockerfile('api', './api') .ContainerResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ContainerResource (+2 overloads)
Adds a reference to another resource
withReference(const db: PostgresDatabaseResource
db) .ContainerResource.withHttpEndpoint(options?: { port?: number; targetPort?: number; name?: string; env?: string; isProxied?: boolean;} | undefined): ContainerResource (+1 overload)
Adds an HTTP endpoint
withHttpEndpoint({ port?: number | undefined
port: 8080, targetPort?: number | undefined
targetPort: 8080, name?: string | undefined
name: 'http' });
await const builder: IDistributedApplicationBuilder
builder .IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, options?: { dockerfilePath?: string; stage?: string;}): ContainerResource (+1 overload)
Adds a container resource built from a Dockerfile
addDockerfile('web', './web') .ContainerResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): ContainerResource (+2 overloads)
Adds a reference to another resource
withReference(const api: ContainerResource
api) .ContainerResource.withHttpEndpoint(options?: { port?: number; targetPort?: number; name?: string; env?: string; isProxied?: boolean;} | undefined): ContainerResource (+1 overload)
Adds an HTTP endpoint
withHttpEndpoint({ port?: number | undefined
port: 3000, targetPort?: number | undefined
targetPort: 3000, name?: string | undefined
name: 'http' });
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();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.
For more examples, see Project resources, C# file-based apps, Executable resources, and Migrate from Docker Compose.
Add telemetry configuration (optional)
Section titled “Add telemetry configuration (optional)”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.
If your app includes C# services, ServiceDefaults is the standard way to add observability, resilience, and health checks.
-
Create a ServiceDefaults project and reference it from your service:
Add ServiceDefaults dotnet new aspire-servicedefaults -n YourProject.ServiceDefaultsdotnet sln add YourProject.ServiceDefaultsdotnet add YourProject reference YourProject.ServiceDefaults -
Update your service’s
Program.cs:Program.cs — Add ServiceDefaults var builder = WebApplication.CreateBuilder(args);builder.AddServiceDefaults();var app = builder.Build();app.MapDefaultEndpoints();app.Run();
For more information, see Service Defaults.
If your app includes Node.js or TypeScript services, configure OpenTelemetry inside the service and point it at the Aspire OTLP endpoint.
-
Install the OpenTelemetry packages:
Install OpenTelemetry packages npm install @opentelemetry/api @opentelemetry/sdk-node \@opentelemetry/auto-instrumentations-node \@opentelemetry/exporter-trace-otlp-grpc \@opentelemetry/exporter-metrics-otlp-grpc -
Create a telemetry bootstrap file:
telemetry.ts import { NodeSDK } from '@opentelemetry/sdk-node';import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';const sdk = new NodeSDK({instrumentations: [getNodeAutoInstrumentations()],});sdk.start(); -
Import it first in your app entry point:
src/server.ts import './telemetry';import express from 'express';const app = express();
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.
Run and verify
Section titled “Run and verify”Once the AppHost captures the resources and relationships you care about, start everything together with the Aspire CLI.
-
From the directory that contains your AppHost, run:
Run your application with Aspire aspire run -
Wait for the CLI to discover the AppHost, launch the resources, and print the dashboard URL.
Example output Finding apphosts...Dashboard: https://localhost:17068/login?t=examplePress CTRL+C to stop the apphost and exit. -
Open the dashboard in your browser and verify:
- All resources start successfully
- Service dependencies appear in the expected order
- Logs, traces, and metrics are visible
- Endpoints and environment variables look correct
-
Exercise the actual app flows you care about, such as frontend-to-API calls, worker jobs, or database access.
-
Stop the system by pressing
⌃+C ⌃+C Control + C CtrlC Control + C CtrlC in your terminal.
Next steps
Section titled “Next steps”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
- Follow Deploy your first app when you are ready to move beyond local orchestration
- Use the Aspire extension for VS Code to run and inspect your app from the editor
- Check the Troubleshooting guide for common setup issues
- Ask questions and share feedback on Discord