From 014502ddabe90d20169a4cea33846e7b57796e3c Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sat, 21 Mar 2026 23:20:39 -0700 Subject: [PATCH 1/4] Reframe existing app guide for JS and TS AppHosts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../get-started/add-aspire-existing-app.mdx | 242 ++++++++++++------ 1 file changed, 169 insertions(+), 73 deletions(-) diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx index 0b51b4f10..d4a5ef9bc 100644 --- a/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx @@ -11,7 +11,7 @@ import PivotSelector from '@components/PivotSelector.astro'; import Pivot from '@components/Pivot.astro'; +The language of the app you're bringing to Aspire doesn't have to match the language of the AppHost. Your services can stay in C#, Python, or JavaScript while Aspire uses a separate AppHost to orchestrate them. + +This guide groups examples by the language of the existing apps you're adding. The JavaScript walkthrough uses a TypeScript AppHost so JavaScript developers can stay in the same toolchain end-to-end. If you prefer a different AppHost language, use `aspire init --language ...` to choose it explicitly. + + :::note[Definition]{icon="approve-check-circle"} **Aspireify** (verb): To transform an existing application into a distributed, observable, and orchestrated system by adding Aspire—no cape required, just a few commands! ::: @@ -115,7 +121,7 @@ Adding Aspire to an existing application follows these key steps: ## Initialize Aspire support -The `aspire init` command is the starting point for adding Aspire to your existing application. This command analyzes your project structure and adds an AppHost that orchestrates your services. +The `aspire init` command is the starting point for adding Aspire to your existing application. It adds an AppHost that orchestrates your services while letting those services stay in their current languages. @@ -139,9 +145,20 @@ The `aspire init` command is the starting point for adding Aspire to your existi 2. Run `aspire init` to initialize Aspire support: + ```bash title="Initialize Aspire" aspire init ``` + + + ```bash title="Initialize Aspire with a TypeScript AppHost" + aspire init --language typescript + ``` + + + The `aspire init` command runs in **interactive mode** by default. It will: @@ -150,19 +167,19 @@ The `aspire init` command is the starting point for adding Aspire to your existi - Create a project-based AppHost (an _AppHost_ project with `AppHost.cs`) - Analyze your projects and suggest which ones to add to the orchestration - Install necessary Aspire packages - - - - Detect your existing project structure - - Create a file-based AppHost (`apphost.cs`) - - Analyze your Python applications and suggest which ones to add to the orchestration - - Install necessary Aspire packages - - - - Detect your existing workspace structure - - Create a file-based AppHost (`apphost.cs`) - - Analyze your JavaScript/Node.js applications and suggest which ones to add to the orchestration - - Install necessary Aspire packages - + + + - Detect your existing project structure + - Ask which AppHost language to create + - Create a file-based C# AppHost (`apphost.cs`) or a TypeScript AppHost (`apphost.ts`) + - Install the supporting packages for that AppHost + + + - Detect your existing workspace structure + - Create a TypeScript AppHost (`apphost.ts`) + - Add the generated AppHost SDK and config files + - Install the supporting Node.js dependencies for the AppHost + For more details on the `aspire init` command and its options, see the [CLI reference: `aspire init`](/reference/cli/commands/aspire-init/). @@ -222,12 +239,15 @@ After running `aspire init`, your project will have a file-based AppHost: A typical SaaS application with FastAPI backend, Flask frontend, and Celery worker. -After running `aspire init`, your project will have a file-based AppHost: +After running `aspire init --language typescript`, your project will have a TypeScript AppHost: - my-store/ - - **apphost.cs** (new) orchestration code - - **apphost.run.json** (new) configuration + - **apphost.ts** (new) orchestration code + - **.modules/** (new) generated SDK + - **aspire.config.json** (new) configuration + - **package.json** (new) AppHost dependencies + - **tsconfig.json** (new) TypeScript configuration - packages/ - api/ - src/ @@ -278,16 +298,21 @@ builder.Build().Run(); -The `apphost.cs` file initially contains a minimal starter: +The `apphost.ts` file initially contains a minimal starter: -```csharp title="apphost.cs — Initial state after aspire init" -#:sdk Aspire.AppHost.Sdk@13.1.0 +```typescript title="apphost.ts — Initial state after aspire init" +// Aspire TypeScript AppHost +// For more information, see: https://aspire.dev -var builder = DistributedApplication.CreateBuilder(args); +import { createBuilder } from './.modules/aspire.js'; -// TODO: Add resources here +const builder = await createBuilder(); -builder.Build().Run(); +// Add your resources here, for example: +// const redis = await builder.addContainer("cache", "redis:latest"); +// const postgres = await builder.addPostgres("db"); + +await builder.build().run(); ``` @@ -316,15 +341,17 @@ This package provides methods like `AddUvicornApp`, `AddPythonApp`, and `AddPyth -For JavaScript/TypeScript applications, install the JavaScript hosting package: +For JavaScript/TypeScript applications, add the JavaScript hosting integration to your AppHost: - +```bash title="Aspire CLI — Add JavaScript hosting integration" +aspire add javascript +``` -This package provides methods like `AddViteApp`, `AddNodeApp`, and `AddJavaScriptApp`. +This updates the generated AppHost SDK with methods like `addViteApp`, `addNodeApp`, and `addJavaScriptApp`. -### Add project references +### Add C# project references @@ -348,6 +375,11 @@ This updates the AppHost `.csproj` file with entries like: ``` + + + +This step only applies to C# project-based AppHosts. Python and JavaScript file-based AppHosts don't use `.csproj` project references. + ### Model your resources in the AppHost @@ -355,9 +387,12 @@ This updates the AppHost `.csproj` file with entries like: Now update your `AppHost.cs` file in the AppHost project to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. - + Now update your `apphost.cs` file to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. + +Now update your `apphost.ts` file to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. + @@ -429,47 +464,50 @@ builder.Build().Run(); For JavaScript applications, use the appropriate method based on your application type: -```csharp title="apphost.cs — Complete monorepo example" -#:sdk Aspire.AppHost.Sdk@13.1.0 -#:package Aspire.Hosting.JavaScript@13.1.0 +```typescript title="apphost.ts — Complete monorepo example" +import { createBuilder } from './.modules/aspire.js'; -var builder = DistributedApplication.CreateBuilder(args); +const builder = await createBuilder(); // Node.js API -var api = builder.AddNodeApp("api", "./packages/api", "src/server.js") - .WithNpm() - .WithHttpHealthCheck("/health"); +const api = await builder + .addNodeApp("api", "./packages/api", "src/server.js") + .withNpm() + .withHttpHealthCheck({ path: "/health" }); // React storefront -var web = builder.AddViteApp("web", "./packages/web") - .WithExternalHttpEndpoints() - .WithReference(api) - .WaitFor(api); +const web = await builder + .addViteApp("web", "./packages/web") + .withExternalHttpEndpoints() + .withReference(api) + .waitFor(api); // Admin dashboard -var admin = builder.AddViteApp("admin", "./packages/admin") - .WithExternalHttpEndpoints() - .WithReference(api) - .WaitFor(api); +const admin = await builder + .addViteApp("admin", "./packages/admin") + .withExternalHttpEndpoints() + .withReference(api) + .waitFor(api); -builder.Build().Run(); +await builder.build().run(); ``` **Key methods:** -- `AddViteApp` - For Vite-based applications (React, Vue, Svelte) -- `AddNodeApp` - For Node.js applications -- `AddJavaScriptApp` - For generic JavaScript applications with npm/yarn/pnpm - - `WithNpm()` / `WithYarn()` / `WithPnpm()` - Specify package manager -- `WithRunScript` - Specify which npm script to run during development +- `addViteApp` - For Vite-based applications (React, Vue, Svelte) +- `addNodeApp` - For Node.js applications +- `addJavaScriptApp` - For generic JavaScript applications with npm/yarn/pnpm + - `withNpm()` / `withYarn()` / `withPnpm()` - Specify package manager +- `withRunScript` - Specify which npm script to run during development :::note[Passing arguments to scripts] -Unlike the deprecated `AddNpmApp` API in Aspire 9, the new JavaScript hosting methods (`AddJavaScriptApp`, `AddViteApp`, `AddNodeApp`) do not support an `args` constructor parameter. You have two options to pass arguments to your scripts: +Unlike the deprecated `AddNpmApp` API in Aspire 9, the new JavaScript hosting methods (`addJavaScriptApp`, `addViteApp`, `addNodeApp`) do not support an `args` constructor parameter. You have two options to pass arguments to your scripts: -**Option 1: Use `WithArgs` to pass arguments directly** +**Option 1: Use `withArgs` to pass arguments directly** -```csharp title="apphost.cs — Pass arguments using WithArgs" -builder.AddViteApp("frontend", "./frontend") - .WithArgs("--no-open"); +```typescript title="apphost.ts — Pass arguments using withArgs" +await builder + .addViteApp("frontend", "./frontend") + .withArgs(["--no-open"]); ``` **Option 2: Define custom scripts in `package.json` with arguments** @@ -483,9 +521,10 @@ builder.AddViteApp("frontend", "./frontend") } ``` -```csharp title="apphost.cs — Reference custom script" -builder.AddViteApp("frontend", "./frontend") - .WithRunScript("dev:no-open"); +```typescript title="apphost.ts — Reference custom script" +await builder + .addViteApp("frontend", "./frontend") + .withRunScript("dev:no-open"); ``` Option 2 keeps all script configuration in `package.json`, making your scripts more discoverable and easier to run outside of Aspire (e.g., `npm run dev:no-open`). @@ -494,16 +533,16 @@ Option 2 keeps all script configuration in `package.json`, making your scripts m ### Connect services -The calls to `WithReference` establish service dependencies and enable service discovery: +The `WithReference` / `withReference` calls establish service dependencies and enable service discovery: -```csharp title="AppHost.cs — Connect .NET services" ".WithReference" +```csharp title="AppHost.cs — Connect C# services" ".WithReference" // Omitted for brevity... var api = builder.AddProject("api"); @@ -535,14 +574,16 @@ var worker = builder.AddPythonApp("worker", "../python-worker", "worker.py") -```csharp title="apphost.cs — Connect JavaScript services" ".WithReference" +```typescript title="apphost.ts — Connect JavaScript services" ".withReference" // Omitted for brevity... -var api = builder.AddNodeApp("api", "../node-api", "server.js") - .WithNpm(); +const api = await builder + .addNodeApp("api", "../node-api", "server.js") + .withNpm(); -var frontend = builder.AddViteApp("frontend", "../react-frontend") - .WithReference(api); // Frontend gets API_HTTP and API_HTTPS env vars +await builder + .addViteApp("frontend", "../react-frontend") + .withReference(api); // Frontend gets API_HTTP and API_HTTPS env vars // Omitted for brevity... ``` @@ -718,11 +759,13 @@ When you add a hosting integration (like Redis) to your AppHost and reference it aspire add redis ``` - This command adds the necessary NuGet packages and helps you configure the integration. + This command adds the necessary AppHost dependencies and helps you configure the integration. 3. Update your AppHost to reference the integration and share it across all your services: - ```csharp title="apphost.cs — Add Redis integration for multi-language apps" + + + ```csharp title="apphost.cs — Add Redis integration for multiple services" var builder = DistributedApplication.CreateBuilder(args); // Add Redis resource @@ -744,6 +787,31 @@ When you add a hosting integration (like Redis) to your AppHost and reference it builder.Build().Run(); ``` + + + + ```typescript title="apphost.ts — Add Redis integration for multiple services" + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + + const cache = await builder.addRedis("cache"); + + await builder + .addNodeApp("api", "../node-api", "server.js") + .withNpm() + .withReference(cache); + + await builder + .addNodeApp("worker", "../node-worker", "worker.js") + .withNpm() + .withReference(cache); + + await builder.build().run(); + ``` + + + 4. Configure the integration in each language: @@ -809,15 +877,15 @@ Now that you've added Aspire to your application, it's time to run it and see th -1. From your solution directory, run the application using the Aspire CLI: +1. From your app root, run the application using the Aspire CLI: ```bash title="Run your application with Aspire" aspire run ``` The Aspire CLI will: - - Find your AppHost (file-based `apphost.cs`) - - Build your solution + - Find your AppHost + - Build your app and its dependencies - Launch all orchestrated services - Start the Aspire dashboard @@ -825,7 +893,6 @@ Now that you've added Aspire to your application, it's time to run it and see th ```bash title="Example output" mark={4} 🔍 Finding apphosts... - apphost.cs Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 @@ -834,6 +901,8 @@ Now that you've added Aspire to your application, it's time to run it and see th Press CTRL+C to stop the apphost and exit. ``` + The CLI output also shows which AppHost Aspire found, such as `apphost.ts`, `apphost.cs`, or an `AppHost.csproj` file. + 3. Open the dashboard in your browser using the provided URL. You'll see: - All your orchestrated resources and their status @@ -891,6 +960,7 @@ services: ``` + ```csharp title="apphost.cs" showLineNumbers var builder = DistributedApplication.CreateBuilder(args); @@ -907,14 +977,40 @@ var web = builder.AddProject("web") builder.Build().Run(); ``` + + +```typescript title="apphost.ts" showLineNumbers +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const db = (await builder.addPostgres("postgres")) + .addDatabase("mydb"); + +const api = await builder + .addNodeApp("api", "./api", "server.js") + .withNpm() + .withReference(db); + +await builder + .addViteApp("web", "./web") + .withExternalHttpEndpoints() + .withReference(api) + .waitFor(api); + +await builder.build().run(); +``` + +The exact AppHost methods differ by language and service type, but the orchestration pattern is the same: model the shared dependencies once, then connect services with `WithReference` / `withReference`. + **Key advantages of Aspire over Docker Compose:** - **Literally, less verbose** — Yet, more expressive and powerful. - **No manual URL configuration** — Services discover each other automatically. -- **Type-safe references** — Compile-time checking for service dependencies. +- **Code-based resource references** — Define service dependencies in code instead of duplicating them in YAML. - **Built-in dashboard** — Observability without additional tools like Prometheus/Grafana. - **Development and deployment** — Same orchestration code works locally and can generate Docker Compose or deploy anywhere. - **Integration libraries** — Pre-built support for databases, caches, message queues with best practices. From 38a50b2c8dbdf89d5bdb6ed4c449624fac368832 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sat, 21 Mar 2026 23:47:37 -0700 Subject: [PATCH 2/4] Group getting started docs by AppHost language Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/frontend/config/sidebar/docs.topics.ts | 32 +- ...add-aspire-existing-app-csharp-apphost.mdx | 955 +++++++++++++++ ...aspire-existing-app-typescript-apphost.mdx | 582 +++++++++ .../get-started/add-aspire-existing-app.mdx | 1051 +---------------- .../get-started/first-app-csharp-apphost.mdx | 373 ++++++ .../first-app-typescript-apphost.mdx | 262 ++++ .../content/docs/get-started/first-app.mdx | 511 +------- 7 files changed, 2248 insertions(+), 1518 deletions(-) create mode 100644 src/frontend/src/content/docs/get-started/add-aspire-existing-app-csharp-apphost.mdx create mode 100644 src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx create mode 100644 src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx create mode 100644 src/frontend/src/content/docs/get-started/first-app-typescript-apphost.mdx diff --git a/src/frontend/config/sidebar/docs.topics.ts b/src/frontend/config/sidebar/docs.topics.ts index 29ed41da6..bbc9f5ab6 100644 --- a/src/frontend/config/sidebar/docs.topics.ts +++ b/src/frontend/config/sidebar/docs.topics.ts @@ -271,6 +271,7 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { }, { label: 'Build your first app', + collapsed: false, translations: { da: 'Byg din første app', de: 'Erstellen Sie Ihre erste App', @@ -289,7 +290,6 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { uk: 'Створіть свій перший додаток', 'zh-CN': '构建您的第一个应用', }, - slug: 'get-started/first-app', badge: { text: 'Quickstart', variant: 'tip', @@ -312,6 +312,20 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { 'zh-CN': '快速开始', }, }, + items: [ + { + label: 'Overview', + slug: 'get-started/first-app', + }, + { + label: 'C# AppHost', + slug: 'get-started/first-app-csharp-apphost', + }, + { + label: 'TypeScript AppHost', + slug: 'get-started/first-app-typescript-apphost', + }, + ], }, { label: 'Deploy your first app', @@ -358,6 +372,7 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { }, { label: 'Aspireify an existing app', + collapsed: false, translations: { da: 'Aspireify en eksisterende app', de: 'Eine bestehende App Aspireify', @@ -376,7 +391,20 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { uk: 'Aspireify наявний застосунок', 'zh-CN': '对现有应用进行 Aspireify', }, - slug: 'get-started/add-aspire-existing-app', + items: [ + { + label: 'Overview', + slug: 'get-started/add-aspire-existing-app', + }, + { + label: 'C# AppHost', + slug: 'get-started/add-aspire-existing-app-csharp-apphost', + }, + { + label: 'TypeScript AppHost', + slug: 'get-started/add-aspire-existing-app-typescript-apphost', + }, + ], }, { label: 'Use AI coding agents', diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app-csharp-apphost.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-csharp-apphost.mdx new file mode 100644 index 000000000..d3df44ee5 --- /dev/null +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-csharp-apphost.mdx @@ -0,0 +1,955 @@ +--- +title: "Aspireify an existing app with a C# AppHost" +description: "Learn how to add Aspire orchestration to an existing application by using a C# AppHost." +prev: false +next: false +--- + +import { Aside, Steps, FileTree, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components' +import LearnMore from '@components/LearnMore.astro'; +import InstallPackage from '@components/InstallPackage.astro'; +import PivotSelector from '@components/PivotSelector.astro'; +import Pivot from '@components/Pivot.astro'; + + + + +This guide shows you how to add Aspire orchestration to an existing application while using a C# AppHost (`AppHost.cs` or `apphost.cs`). Choose the app stack you're bringing to Aspire, then initialize the AppHost, register your resources, and run everything locally with Aspire. + +:::note[Definition]{icon="approve-check-circle"} +**Aspireify** (verb): To transform an existing application into a distributed, observable, and orchestrated system by adding Aspire—no cape required, just a few commands! +::: + +## Why add Aspire to an existing app? + +As distributed applications grow, coordinating multiple services becomes a tangled web of configuration files, hard-coded URLs, and fragile startup scripts. You're juggling connection strings across environments, manually wiring service dependencies, and struggling to trace issues across your microservices. Development setup becomes a ritual of precision—start the database, then the cache, then service A before service B—and any misstep sends you back to square one. + +Aspire cuts through this complexity with a unified orchestration layer that treats your entire application as a cohesive system. Define your services and their relationships once in code ([the AppHost](/get-started/app-host/)), and Aspire handles service discovery, injects configuration automatically, and provides a dashboard with logs, traces, and metrics out of the box. Whether you're orchestrating C#, Python, or JavaScript services—or all three together—you get the same consistent experience from development through deployment. + +The best part? You can adopt Aspire incrementally. Start with orchestration, add observability when you're ready, integrate external services as needed. Your existing codebase stays largely unchanged, and you can reverse course if Aspire isn't the right fit. + +## Prerequisites + +Before you begin, ensure you have the following prerequisites installed based on your application's language: + +### Common requirements + +- [.NET SDK 10.0 or later](/get-started/prerequisites/) — Required for the Aspire AppHost, regardless of your application's language. +- [Aspire CLI installed](/get-started/install-cli/) — For orchestration and deployment commands. +- An existing application to add Aspire to. + +### Language-specific requirements + + + +**For C# applications:** + +- A solution with one or more .NET or ASP.NET Core projects (`.csproj`) +- Visual Studio 2022 17.13 or later, Visual Studio Code, or JetBrains Rider (optional) + +**Example project types:** +- ASP.NET Core Minimal API +- ASP.NET Core Razor Pages or Blazor applications +- Console applications +- Worker services +- gRPC services +- Azure Functions + + + + +**For Python applications:** + +- [Python 3.10 or later](https://www.python.org/downloads/) installed +- [uv](https://docs.astral.sh/uv/) (recommended) or pip for package management +- An existing Python application + +**Example application types:** +- FastAPI web applications +- Flask web applications +- Django applications +- Python scripts or worker processes +- Streamlit or other Python web frameworks + + + + +**For JavaScript/TypeScript applications:** + +- [Node.js 22 or later](https://nodejs.org/) installed +- npm, yarn, or pnpm for package management +- An existing JavaScript/TypeScript application + +**Example application types:** +- React, Vue, or Svelte applications (especially Vite-based) +- Node.js/Express APIs +- Next.js applications +- Angular applications +- TypeScript backend services + + + + + +## Overview of the process + +Adding Aspire to an existing application follows these key steps: + + + +1. **Initialize Aspire support** — Use `aspire init` to add the AppHost (orchestration layer) +2. **Add your applications** — Register C#, Python, and JavaScript applications in the AppHost +3. **Configure telemetry (optional)** — Add OpenTelemetry instrumentation for observability +4. **Add integrations (optional)** — Connect to databases, caches, and message queues +5. **Run and verify** — Test your application with Aspire orchestration + + + +## Initialize Aspire support + +The `aspire init` command is the starting point for adding Aspire to your existing application. This command analyzes your project structure and adds an AppHost that orchestrates your services. + + + +1. Navigate to your project directory: + + + ```bash title="Navigate to your solution directory" + cd /path/to/your-solution + ``` + + + ```bash title="Navigate to your project root" + cd /path/to/your-project + ``` + + + ```bash title="Navigate to your workspace root" + cd /path/to/your-workspace + ``` + + +2. Run `aspire init` to initialize Aspire support: + + ```bash title="Initialize Aspire" + aspire init + ``` + + The `aspire init` command runs in **interactive mode** by default. It will: + + + - Detect your existing solution structure + - Create a project-based AppHost (an _AppHost_ project with `AppHost.cs`) + - Analyze your projects and suggest which ones to add to the orchestration + - Install necessary Aspire packages + + + - Detect your existing project structure + - Create a file-based AppHost (`apphost.cs`) + - Analyze your Python applications and suggest which ones to add to the orchestration + - Install necessary Aspire packages + + + - Detect your existing workspace structure + - Create a file-based AppHost (`apphost.cs`) + - Analyze your JavaScript/Node.js applications and suggest which ones to add to the orchestration + - Install necessary Aspire packages + + + + For more details on the `aspire init` command and its options, see the [CLI reference: `aspire init`](/reference/cli/commands/aspire-init/). + + + + +### What does `aspire init` create? + + +After running `aspire init`, your solution will have a project-based AppHost: + + +- ExampleEcommerce.sln (updated) +- src/ + - **ExampleEcommerce.AppHost/** (new) orchestration project + - **ExampleEcommerce.AppHost.csproj** project file + - **AppHost.cs** orchestration code + - Api/ + - ExampleEcommerce.Api.csproj + - Program.cs + - Controllers/ + - Web/ + - ExampleEcommerce.Web.csproj + - Program.cs + - Pages/ + - OrderProcessor/ + - ExampleEcommerce.OrderProcessor.csproj + - Worker.cs + + +A typical e-commerce solution with a web frontend, API service, and background worker. + + +After running `aspire init`, your project will have a file-based AppHost: + + +- my-saas-app/ + - **apphost.cs** (new) orchestration code + - **apphost.run.json** (new) configuration + - api/ + - main.py + - routers/ + - models/ + - pyproject.toml + - frontend/ + - app.py + - templates/ + - static/ + - requirements.txt + - worker/ + - tasks.py + - celery_config.py + - requirements.txt + + +A typical SaaS application with FastAPI backend, Flask frontend, and Celery worker. + + +After running `aspire init`, your project will have a file-based AppHost: + + +- my-store/ + - **apphost.cs** (new) orchestration code + - **apphost.run.json** (new) configuration + - packages/ + - api/ + - src/ + - server.js + - routes/ + - package.json + - web/ + - src/ + - App.tsx + - components/ + - package.json + - vite.config.ts + - admin/ + - src/ + - main.ts + - views/ + - package.json + - package.json (workspace root) + + +A typical monorepo with Node.js API, React storefront, and admin dashboard. + + + +The `AppHost.cs` file in your new AppHost project initially contains a minimal starter: + +```csharp title="AppHost.cs — Initial state after aspire init" +var builder = DistributedApplication.CreateBuilder(args); + +// TODO: Add resources here + +builder.Build().Run(); +``` + + + +The `apphost.cs` file initially contains a minimal starter: + +```csharp title="apphost.cs — Initial state after aspire init" +#:sdk Aspire.AppHost.Sdk@13.1.0 + +var builder = DistributedApplication.CreateBuilder(args); + +// TODO: Add resources here + +builder.Build().Run(); +``` + + + +The `apphost.cs` file initially contains a minimal starter: + +```csharp title="apphost.cs — Initial state after aspire init" +#:sdk Aspire.AppHost.Sdk@13.1.0 + +var builder = DistributedApplication.CreateBuilder(args); + +// TODO: Add resources here + +builder.Build().Run(); +``` + + + +This is your starting point. In the next section, you'll add your applications and configure their relationships. + +## Add your applications to the AppHost + +Once you have an AppHost, you need to register your existing applications. First, install the appropriate hosting packages for your application types, then add your resources to the AppHost. + +### Install hosting packages + + + +For C# projects, if you're using project-based orchestration (`.csproj` files), no additional packages are needed. The base Aspire SDK includes support for `AddProject` (or `AddCSharpApp` for file-based apps). + + + + +For Python applications, install the Python hosting package: + + + +This package provides methods like `AddUvicornApp`, `AddPythonApp`, and `AddPythonModule`. + + + + +For JavaScript/TypeScript applications, install the JavaScript hosting package: + + + +This package provides methods like `AddViteApp`, `AddNodeApp`, and `AddJavaScriptApp`. + + + +### Add C# project references + + + +Before you can use `AddProject` in your AppHost, the AppHost project must have a project reference to each C# project it orchestrates. These project references are what generate the `Projects.YourProject` marker types used by `AddProject`. + +If you used `aspire init`, it likely added these references automatically for the projects you selected. If you need to add more projects later, run the following commands from your AppHost project directory: + +```bash title=".NET CLI — Add project references to AppHost" +dotnet add reference ../Api/ExampleCommerce.Api.csproj +dotnet add reference ../Web/ExampleCommerce.Web.csproj +dotnet add reference ../OrderProcessor/ExampleCommerce.OrderProcessor.csproj +``` + +This updates the AppHost `.csproj` file with entries like: + +```xml title="ExampleCommerce.AppHost.csproj — Project references" + + + + + +``` + + + + +This step only applies to C# project-based AppHosts. Python and JavaScript application resources don't use `.csproj` project references. + + + +### Model your resources in the AppHost + + +Now update your `AppHost.cs` file in the AppHost project to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. + + +Now update your `apphost.cs` file to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. + + + + +For C# projects, use `AddProject` to reference your existing C# projects: + +```csharp title="AppHost.cs — Complete e-commerce example" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api") + .WithHttpHealthCheck("/health"); + +var web = builder.AddProject("web") + .WithExternalHttpEndpoints() + .WithReference(api) + .WaitFor(api); + +var orderProcessor = builder.AddProject("orderprocessor") + .WithReference(api); + +builder.Build().Run(); +``` + +**Key methods:** +- `AddProject` - Adds a .NET project from your solution +- `WithHttpHealthCheck` - Monitors service health via HTTP endpoint +- `WithReference` - Enables service-to-service communication +- `WaitFor` - Ensures proper startup order + + + + +Aspire provides several methods for Python applications: + +```csharp title="apphost.cs — Complete SaaS example" +#:sdk Aspire.AppHost.Sdk@13.1.0 +#:package Aspire.Hosting.Python@13.1.0 + +var builder = DistributedApplication.CreateBuilder(args); + +// FastAPI backend +var api = builder.AddUvicornApp("api", "./api", "main:app") + .WithUv() + .WithHttpHealthCheck("/health"); + +// Flask frontend +var frontend = builder.AddUvicornApp("frontend", "./frontend", "app:app") + .WithUv() + .WithExternalHttpEndpoints() + .WithReference(api) + .WaitFor(api); + +// Celery worker +var worker = builder.AddPythonApp("worker", "./worker", "celery") + .WithUv() + .WithArgs("worker", "-A", "tasks") + .WithReference(api); + +builder.Build().Run(); +``` + +**Key methods:** +- `AddUvicornApp` - For FastAPI, Flask, and other ASGI/WSGI frameworks +- `AddPythonApp` - For standalone Python scripts +- `WithUv()` - Use uv for fast package management (recommended) +- `WithPip()` - Use traditional pip for package management + + + + +For JavaScript applications, use the appropriate method based on your application type: + +```csharp title="apphost.cs — Complete monorepo example" +#:sdk Aspire.AppHost.Sdk@13.1.0 +#:package Aspire.Hosting.JavaScript@13.1.0 + +var builder = DistributedApplication.CreateBuilder(args); + +// Node.js API +var api = builder.AddNodeApp("api", "./packages/api", "src/server.js") + .WithNpm() + .WithHttpHealthCheck("/health"); + +// React storefront +var web = builder.AddViteApp("web", "./packages/web") + .WithExternalHttpEndpoints() + .WithReference(api) + .WaitFor(api); + +// Admin dashboard +var admin = builder.AddViteApp("admin", "./packages/admin") + .WithExternalHttpEndpoints() + .WithReference(api) + .WaitFor(api); + +builder.Build().Run(); +``` + +**Key methods:** +- `AddViteApp` - For Vite-based applications (React, Vue, Svelte) +- `AddNodeApp` - For Node.js applications +- `AddJavaScriptApp` - For generic JavaScript applications with npm/yarn/pnpm + - `WithNpm()` / `WithYarn()` / `WithPnpm()` - Specify package manager +- `WithRunScript` - Specify which npm script to run during development + +:::note[Passing arguments to scripts] +Unlike the deprecated `AddNpmApp` API in Aspire 9, the new JavaScript hosting methods (`AddJavaScriptApp`, `AddViteApp`, `AddNodeApp`) do not support an `args` constructor parameter. You have two options to pass arguments to your scripts: + +**Option 1: Use `WithArgs` to pass arguments directly** + +```csharp title="apphost.cs — Pass arguments using WithArgs" +builder.AddViteApp("frontend", "./frontend") + .WithArgs("--no-open"); +``` + +**Option 2: Define custom scripts in `package.json` with arguments** + +```json title="package.json" +{ + "scripts": { + "dev": "vite", + "dev:no-open": "vite --no-open" + } +} +``` + +```csharp title="apphost.cs — Reference custom script" +builder.AddViteApp("frontend", "./frontend") + .WithRunScript("dev:no-open"); +``` + +Option 2 keeps all script configuration in `package.json`, making your scripts more discoverable and easier to run outside of Aspire (e.g., `npm run dev:no-open`). +::: + + + + + +### Connect services + +The `WithReference` calls establish service dependencies and enable service discovery: + + + +```csharp title="AppHost.cs — Connect C# services" ".WithReference" +// Omitted for brevity... + +var api = builder.AddProject("api"); + +var web = builder.AddProject("web") + .WithReference(api); // Web can call API + +var worker = builder.AddProject("worker") + .WithReference(api); // Worker can call API + +// Omitted for brevity... +``` + + + + +```csharp title="apphost.cs — Connect Python services" ".WithReference" +// Omitted for brevity... + +var api = builder.AddUvicornApp("api", "../python-api", "main:app") + .WithUv(); + +var worker = builder.AddPythonApp("worker", "../python-worker", "worker.py") + .WithReference(api); // Worker gets API_HTTP and API_HTTPS env vars + +// Omitted for brevity... +``` + + + + +```csharp title="apphost.cs — Connect JavaScript services" ".WithReference" +// Omitted for brevity... + +var api = builder.AddNodeApp("api", "../node-api", "server.js") + .WithNpm(); + +var frontend = builder.AddViteApp("frontend", "../react-frontend") + .WithReference(api); // Frontend gets API_HTTP and API_HTTPS env vars + +// Omitted for brevity... +``` + + + +When you call `WithReference`, you're declaring a dependency between resources. Aspire handles the rest—automatically injecting configuration at runtime and during deployment so your services can communicate seamlessly, whether running locally or in production. + +## Add telemetry configuration (optional) + + + +ServiceDefaults provide a standardized way to add observability, resilience, and health checks to .NET services. This step is optional but recommended for production applications. + + + +1. During the `aspire init` process, you may be prompted to add ServiceDefaults. If you chose not to add it initially, you can add it later using the Aspire CLI or manually. + +2. To add ServiceDefaults to a project manually: + + ```bash title=".NET CLI — Add ServiceDefaults to your project" + dotnet new aspire-servicedefaults -n YourProject.ServiceDefaults + dotnet sln add YourProject.ServiceDefaults + dotnet add YourProject reference YourProject.ServiceDefaults + ``` + +3. Update your project's `Program.cs` to use ServiceDefaults: + + ```csharp title="Program.cs — Add ServiceDefaults" + var builder = WebApplication.CreateBuilder(args); + + // Add Aspire ServiceDefaults for observability and resilience + builder.AddServiceDefaults(); + + // ... your existing service configuration ... + + var app = builder.Build(); + + // Map Aspire ServiceDefaults endpoints + app.MapDefaultEndpoints(); + + // ... your existing middleware ... + + app.Run(); + ``` + + + + + For more information on ServiceDefaults, see [Service Defaults](/fundamentals/service-defaults/). + + + + + +Python applications can send telemetry to the Aspire dashboard using OpenTelemetry: + + + +1. Install OpenTelemetry packages in your Python application: + + ```bash title="Install OpenTelemetry packages" + uv add opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc + uv add opentelemetry-instrumentation-fastapi # For FastAPI + # Or for Flask: + # uv add opentelemetry-instrumentation-flask + ``` + +2. Configure OpenTelemetry in your Python application: + + ```python title="Python — Configure OpenTelemetry" + import os + from opentelemetry import trace, metrics + from opentelemetry.sdk.trace import TracerProvider + from opentelemetry.sdk.metrics import MeterProvider + from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter + from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter + from opentelemetry.sdk.resources import Resource + from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor + + # Get OTLP endpoint from environment (injected by Aspire) + otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT") + + # Configure tracing and metrics + resource = Resource.create({"service.name": "api"}) + trace.set_tracer_provider(TracerProvider(resource=resource)) + metrics.set_meter_provider(MeterProvider(resource=resource)) + + # Instrument your FastAPI app + FastAPIInstrumentor.instrument_app(app) + ``` + + + + + + +JavaScript/Node.js applications can also send telemetry using OpenTelemetry: + + + +1. Install OpenTelemetry packages: + + ```bash title="Install OpenTelemetry packages" + npm install @opentelemetry/api @opentelemetry/sdk-node \ + @opentelemetry/auto-instrumentations-node \ + @opentelemetry/exporter-trace-otlp-grpc \ + @opentelemetry/exporter-metrics-otlp-grpc + ``` + +2. Create a telemetry configuration file: + + ```javascript title="JavaScript — telemetry.js" + const { NodeSDK } = require('@opentelemetry/sdk-node'); + const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); + const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); + const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc'); + const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics'); + const { resourceFromAttributes } = require('@opentelemetry/resources'); + const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions'); + + const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317'; + + // Create resource with service name + const resource = resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'frontend', + }); + + const sdk = new NodeSDK({ + resource: resource, + traceExporter: new OTLPTraceExporter({ url: otlpEndpoint }), + metricReader: new PeriodicExportingMetricReader({ + exporter: new OTLPMetricExporter({ url: otlpEndpoint }) + }), + instrumentations: [getNodeAutoInstrumentations()] + }); + + sdk.start(); + ``` + +3. Import the telemetry configuration at the top of your application entry point: + + ```javascript title="JavaScript — app.js" + // This must be first! + require('./telemetry'); + + const express = require('express'); + // ... rest of your app + ``` + + + + + +## Add integrations (optional) + +Aspire provides integration libraries that simplify working with common services like Redis, PostgreSQL, RabbitMQ, and more. These integrations handle configuration, health checks, and telemetry automatically. + +When you add a hosting integration (like Redis) to your AppHost and reference it from a dependent resource, Aspire automatically injects the necessary configuration. This includes connection strings, URLs, environment variables, and other service-specific settings—eliminating manual connection string management across your services. + + + +1. Identify which services in your application could benefit from Aspire integrations. Common candidates include: + + - Databases (PostgreSQL, SQL Server, MongoDB) + - Caching (Redis, Valkey) + - Messaging (RabbitMQ, Azure Service Bus, Kafka) + - Storage (Azure Blob Storage, AWS S3) + +2. Use the `aspire add` command to add integration packages to your AppHost: + + ```bash title="Add a Redis integration" + aspire add redis + ``` + + This command adds the necessary NuGet packages and helps you configure the integration. + +3. Update your AppHost to reference the integration and share it across all your services: + + ```csharp title="apphost.cs — Add Redis integration for multi-language apps" + var builder = DistributedApplication.CreateBuilder(args); + + // Add Redis resource + var cache = builder.AddRedis("cache"); + + // Share Redis with .NET API + var api = builder.AddProject("api") + .WithReference(cache) + .WithHttpHealthCheck("/health"); + + // Share Redis with Python worker + var pythonWorker = builder.AddPythonApp("worker", "../python-worker", "worker.py") + .WithReference(cache); // Python gets CACHE_HOST, CACHE_PORT env vars + + // Share Redis with Node.js service + var nodeService = builder.AddNodeApp("service", "../node-service", "index.js") + .WithReference(cache); // Node.js gets CACHE_HOST, CACHE_PORT env vars + + builder.Build().Run(); + ``` + +4. Configure the integration in each language: + + + + ```bash title="Add Redis client to .NET project" + dotnet add YourApi package Aspire.StackExchange.Redis + ``` + + ```csharp title="Program.cs — Configure Redis client" + var builder = WebApplication.CreateBuilder(args); + builder.AddRedisClient("cache"); + ``` + + + + + ```bash title="Add Redis client to Python project" + uv add redis + ``` + + ```python title="Python — Configure Redis client" + import os + import redis + + # Aspire injects CACHE_HOST and CACHE_PORT + redis_client = redis.Redis( + host=os.getenv("CACHE_HOST"), + port=int(os.getenv("CACHE_PORT")), + decode_responses=True + ) + ``` + + + + + ```bash title="Add Redis client to Node.js project" + npm install redis + ``` + + ```javascript title="JavaScript — Configure Redis client" + const redis = require('redis'); + + // Aspire injects CACHE_HOST and CACHE_PORT + const client = redis.createClient({ + socket: { + host: process.env.CACHE_HOST, + port: process.env.CACHE_PORT + } + }); + ``` + + + + + + + Browse available integrations in the [Integrations section](/integrations/gallery/). + + +## Run and verify + +Now that you've added Aspire to your application, it's time to run it and see the orchestration in action. + + + +1. From your solution directory, run the application using the Aspire CLI: + + ```bash title="Run your application with Aspire" + aspire run + ``` + + The Aspire CLI will: + - Find your AppHost (file-based `apphost.cs`) + - Build your solution + - Launch all orchestrated services + - Start the Aspire dashboard + +2. The dashboard URL will appear in your terminal output: + + ```bash title="Example output" mark={4} + 🔍 Finding apphosts... + apphost.cs + + Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 + + Logs: ~/.aspire/cli/logs/apphost-13024-2025-11-19-12-00-00.log + + Press CTRL+C to stop the apphost and exit. + ``` + +3. Open the dashboard in your browser using the provided URL. You'll see: + + - All your orchestrated resources and their status + - Real-time logs from each service + - Traces and metrics for observability + - Environment variables and configuration + +4. Verify that your services are running correctly by: + + - Checking the **Resources** page for service health + - Accessing your application endpoints + - Reviewing logs and traces in the dashboard + +5. Stop the application by pressing in your terminal. + + + + + +### Bonus content + +If you're currently using Docker Compose to orchestrate your services, Aspire can replace it while providing additional benefits: + + + +```yaml title="docker-compose.yml" showLineNumbers +services: + postgres: + image: postgres:latest + environment: + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=mydb + ports: + - "5432:5432" + + api: + build: ./api + ports: + - "8080:8080" + environment: + - DATABASE_URL=postgres://postgres:postgres@postgres:5432/mydb + depends_on: + - postgres + + web: + build: ./web + ports: + - "3000:3000" + environment: + - API_URL=http://api:8080 + depends_on: + - api +``` + + +```csharp title="apphost.cs" showLineNumbers +var builder = DistributedApplication.CreateBuilder(args); + +var db = builder.AddPostgres("postgres") + .AddDatabase("mydb"); + +var api = builder.AddProject("api") + .WithReference(db); + +var web = builder.AddProject("web") + .WithExternalHttpEndpoints() + .WithReference(api) + .WaitFor(api); + +builder.Build().Run(); +``` + + + +**Key advantages of Aspire over Docker Compose:** + +- **Literally, less verbose** — Yet, more expressive and powerful. +- **No manual URL configuration** — Services discover each other automatically. +- **Type-safe references** — Compile-time checking for service dependencies. +- **Built-in dashboard** — Observability without additional tools like Prometheus/Grafana. +- **Development and deployment** — Same orchestration code works locally and can generate Docker Compose or deploy anywhere. +- **Integration libraries** — Pre-built support for databases, caches, message queues with best practices. +- **Language-agnostic** — Works with C#, Python, JavaScript, many more, and containerized services. + + + +## Next steps + +Congratulations! You've successfully added Aspire to your existing application. Here are some recommended next steps: + +- **Add more integrations** — Explore [Aspire integrations](/integrations/gallery/) to simplify working with databases, caches, and message queues +- **Configure observability** — Enhance your application's telemetry: + + - Learn about [Service Defaults](/fundamentals/service-defaults/) + + + - See [Standalone dashboard for Python](/dashboard/standalone-for-python/) + + + - See [Standalone dashboard for Node.js](/dashboard/standalone-for-nodejs/) + +- **Deploy your app** — Follow the [Deploy your first app](/get-started/deploy-first-app/) tutorial to deploy your Aspire application +- **Use the VS Code extension** — Run, debug, and manage integrations from within VS Code with the [Aspire extension](/get-started/aspire-vscode-extension/) +- **Explore the dashboard** — Learn more about the [Aspire dashboard](/dashboard/overview/) and its features +- **Learn about multi-language features**: + - [Python support in Aspire](/whats-new/aspire-13/#python-as-a-first-class-citizen) + - [JavaScript support in Aspire](/whats-new/aspire-13/#javascript-as-a-first-class-citizen) diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx new file mode 100644 index 000000000..62e41e758 --- /dev/null +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx @@ -0,0 +1,582 @@ +--- +title: "Aspireify an existing app with a TypeScript AppHost" +description: "Learn how to add Aspire orchestration to an existing JavaScript or TypeScript application by using a TypeScript AppHost." +prev: false +next: false +--- + +import { Aside, Steps, FileTree, Tabs, TabItem } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components' +import LearnMore from '@components/LearnMore.astro'; + + +This guide shows you how to add Aspire orchestration to an existing JavaScript or TypeScript application while using a TypeScript AppHost (`apphost.ts`). You'll initialize Aspire with `aspire init --language typescript`, model your resources in `apphost.ts`, and run the app locally with Aspire. + +:::note[Definition]{icon="approve-check-circle"} +**Aspireify** (verb): To transform an existing application into a distributed, observable, and orchestrated system by adding Aspire—no cape required, just a few commands! +::: + +## Why add Aspire to an existing app? + +As distributed applications grow, coordinating multiple services becomes a tangled web of configuration files, hard-coded URLs, and fragile startup scripts. You're juggling connection strings across environments, manually wiring service dependencies, and struggling to trace issues across your microservices. Development setup becomes a ritual of precision—start the database, then the cache, then service A before service B—and any misstep sends you back to square one. + +Aspire cuts through this complexity with a unified orchestration layer that treats your entire application as a cohesive system. Define your services and their relationships once in code ([the AppHost](/get-started/app-host/)), and Aspire handles service discovery, injects configuration automatically, and provides a dashboard with logs, traces, and metrics out of the box. When you're orchestrating JavaScript and TypeScript services, you get the same consistent experience from development through deployment. + +The best part? You can adopt Aspire incrementally. Start with orchestration, add observability when you're ready, integrate external services as needed. Your existing codebase stays largely unchanged, and you can reverse course if Aspire isn't the right fit. + +## Prerequisites + +Before you begin, ensure you have the following prerequisites installed: + +### Common requirements + +- [.NET SDK 10.0 or later](/get-started/prerequisites/) — Required for the Aspire AppHost, regardless of your application's language. +- [Aspire CLI installed](/get-started/install-cli/) — For orchestration and deployment commands. +- An existing application to add Aspire to. + +### Language-specific requirements + + + +**For JavaScript/TypeScript applications:** + +- [Node.js 22 or later](https://nodejs.org/) installed +- npm, yarn, or pnpm for package management +- An existing JavaScript/TypeScript application + +**Example application types:** +- React, Vue, or Svelte applications (especially Vite-based) +- Node.js/Express APIs +- Next.js applications +- Angular applications +- TypeScript backend services + + + + +## Overview of the process + +Adding Aspire to an existing application follows these key steps: + + + +1. **Initialize Aspire support** — Use `aspire init` to add the AppHost (orchestration layer) +2. **Add your applications** — Register your JavaScript and TypeScript applications in the AppHost +3. **Configure telemetry (optional)** — Add OpenTelemetry instrumentation for observability +4. **Add integrations (optional)** — Connect to databases, caches, and message queues +5. **Run and verify** — Test your application with Aspire orchestration + + + +## Initialize Aspire support + +The `aspire init` command is the starting point for adding Aspire to your existing application. It adds an AppHost that orchestrates your services while letting those services stay in their current languages. + + + +1. Navigate to your project directory: + + + + ```bash title="Navigate to your workspace root" + cd /path/to/your-workspace + ``` + + + +2. Run `aspire init` to initialize Aspire support: + + + ```bash title="Initialize Aspire with a TypeScript AppHost" + aspire init --language typescript + ``` + + + + + + The `aspire init` command runs in **interactive mode** by default. It will: + + + + - Detect your existing workspace structure + - Create a TypeScript AppHost (`apphost.ts`) + - Add the generated AppHost SDK and config files + - Install the supporting Node.js dependencies for the AppHost + + + + + For more details on the `aspire init` command and its options, see the [CLI reference: `aspire init`](/reference/cli/commands/aspire-init/). + + + + +### What does `aspire init` create? + + + +After running `aspire init --language typescript`, your project will have a TypeScript AppHost: + + +- my-store/ + - **apphost.ts** (new) orchestration code + - **.modules/** (new) generated SDK + - **aspire.config.json** (new) configuration + - **package.json** (new) AppHost dependencies + - **tsconfig.json** (new) TypeScript configuration + - packages/ + - api/ + - src/ + - server.js + - routes/ + - package.json + - web/ + - src/ + - App.tsx + - components/ + - package.json + - vite.config.ts + - admin/ + - src/ + - main.ts + - views/ + - package.json + - package.json (workspace root) + + +A typical monorepo with Node.js API, React storefront, and admin dashboard. + + + + +The `apphost.ts` file initially contains a minimal starter: + +```typescript title="apphost.ts — Initial state after aspire init" +// Aspire TypeScript AppHost +// For more information, see: https://aspire.dev + +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// Add your resources here, for example: +// const redis = await builder.addContainer("cache", "redis:latest"); +// const postgres = await builder.addPostgres("db"); + +await builder.build().run(); +``` + + +This is your starting point. In the next section, you'll add your applications and configure their relationships. + +## Add your applications to the AppHost + +Once you have an AppHost, you need to register your existing applications. First, install the appropriate hosting packages for your application types, then add your resources to the AppHost. + +### Install hosting packages + + + +For JavaScript/TypeScript applications, add the JavaScript hosting integration to your AppHost: + +```bash title="Aspire CLI — Add JavaScript hosting integration" +aspire add javascript +``` + +This updates the generated AppHost SDK with methods like `addViteApp`, `addNodeApp`, and `addJavaScriptApp`. + + +### Model your resources in the AppHost + + + +Now update your `apphost.ts` file to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. + + + + +For JavaScript applications, use the appropriate method based on your application type: + +```typescript title="apphost.ts — Complete monorepo example" +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +// Node.js API +const api = await builder + .addNodeApp("api", "./packages/api", "src/server.js") + .withNpm() + .withHttpHealthCheck({ path: "/health" }); + +// React storefront +const web = await builder + .addViteApp("web", "./packages/web") + .withExternalHttpEndpoints() + .withReference(api) + .waitFor(api); + +// Admin dashboard +const admin = await builder + .addViteApp("admin", "./packages/admin") + .withExternalHttpEndpoints() + .withReference(api) + .waitFor(api); + +await builder.build().run(); +``` + +**Key methods:** +- `addViteApp` - For Vite-based applications (React, Vue, Svelte) +- `addNodeApp` - For Node.js applications +- `addJavaScriptApp` - For generic JavaScript applications with npm/yarn/pnpm + - `withNpm()` / `withYarn()` / `withPnpm()` - Specify package manager +- `withRunScript` - Specify which npm script to run during development + +:::note[Passing arguments to scripts] +Unlike the deprecated `AddNpmApp` API in Aspire 9, the new JavaScript hosting methods (`addJavaScriptApp`, `addViteApp`, `addNodeApp`) do not support an `args` constructor parameter. You have two options to pass arguments to your scripts: + +**Option 1: Use `withArgs` to pass arguments directly** + +```typescript title="apphost.ts — Pass arguments using withArgs" +await builder + .addViteApp("frontend", "./frontend") + .withArgs(["--no-open"]); +``` + +**Option 2: Define custom scripts in `package.json` with arguments** + +```json title="package.json" +{ + "scripts": { + "dev": "vite", + "dev:no-open": "vite --no-open" + } +} +``` + +```typescript title="apphost.ts — Reference custom script" +await builder + .addViteApp("frontend", "./frontend") + .withRunScript("dev:no-open"); +``` + +Option 2 keeps all script configuration in `package.json`, making your scripts more discoverable and easier to run outside of Aspire (e.g., `npm run dev:no-open`). +::: + + + + +### Connect services + +The `withReference` calls establish service dependencies and enable service discovery: + + + +```typescript title="apphost.ts — Connect JavaScript services" ".withReference" +// Omitted for brevity... + +const api = await builder + .addNodeApp("api", "../node-api", "server.js") + .withNpm(); + +await builder + .addViteApp("frontend", "../react-frontend") + .withReference(api); // Frontend gets API_HTTP and API_HTTPS env vars + +// Omitted for brevity... +``` + + +When you call `WithReference`, you're declaring a dependency between resources. Aspire handles the rest—automatically injecting configuration at runtime and during deployment so your services can communicate seamlessly, whether running locally or in production. + +## Add telemetry configuration (optional) + + + +JavaScript/Node.js applications can also send telemetry using OpenTelemetry: + + + +1. Install OpenTelemetry packages: + + ```bash title="Install OpenTelemetry packages" + npm install @opentelemetry/api @opentelemetry/sdk-node \ + @opentelemetry/auto-instrumentations-node \ + @opentelemetry/exporter-trace-otlp-grpc \ + @opentelemetry/exporter-metrics-otlp-grpc + ``` + +2. Create a telemetry configuration file: + + ```javascript title="JavaScript — telemetry.js" + const { NodeSDK } = require('@opentelemetry/sdk-node'); + const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); + const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); + const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc'); + const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics'); + const { resourceFromAttributes } = require('@opentelemetry/resources'); + const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions'); + + const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317'; + + // Create resource with service name + const resource = resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'frontend', + }); + + const sdk = new NodeSDK({ + resource: resource, + traceExporter: new OTLPTraceExporter({ url: otlpEndpoint }), + metricReader: new PeriodicExportingMetricReader({ + exporter: new OTLPMetricExporter({ url: otlpEndpoint }) + }), + instrumentations: [getNodeAutoInstrumentations()] + }); + + sdk.start(); + ``` + +3. Import the telemetry configuration at the top of your application entry point: + + ```javascript title="JavaScript — app.js" + // This must be first! + require('./telemetry'); + + const express = require('express'); + // ... rest of your app + ``` + + + + +## Add integrations (optional) + +Aspire provides integration libraries that simplify working with common services like Redis, PostgreSQL, RabbitMQ, and more. These integrations handle configuration, health checks, and telemetry automatically. + +When you add a hosting integration (like Redis) to your AppHost and reference it from a dependent resource, Aspire automatically injects the necessary configuration. This includes connection strings, URLs, environment variables, and other service-specific settings—eliminating manual connection string management across your services. + + + +1. Identify which services in your application could benefit from Aspire integrations. Common candidates include: + + - Databases (PostgreSQL, SQL Server, MongoDB) + - Caching (Redis, Valkey) + - Messaging (RabbitMQ, Azure Service Bus, Kafka) + - Storage (Azure Blob Storage, AWS S3) + +2. Use the `aspire add` command to add integration packages to your AppHost: + + ```bash title="Add a Redis integration" + aspire add redis + ``` + + This command adds the necessary AppHost dependencies and helps you configure the integration. + +3. Update your AppHost to reference the integration and share it across all your services: + + + ```typescript title="apphost.ts — Add Redis integration for multiple services" + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + + const cache = await builder.addRedis("cache"); + + await builder + .addNodeApp("api", "../node-api", "server.js") + .withNpm() + .withReference(cache); + + await builder + .addNodeApp("worker", "../node-worker", "worker.js") + .withNpm() + .withReference(cache); + + await builder.build().run(); + ``` + + + + +4. Configure the integration in each language: + + + + ```bash title="Add Redis client to Node.js project" + npm install redis + ``` + + ```javascript title="JavaScript — Configure Redis client" + const redis = require('redis'); + + // Aspire injects CACHE_HOST and CACHE_PORT + const client = redis.createClient({ + socket: { + host: process.env.CACHE_HOST, + port: process.env.CACHE_PORT + } + }); + ``` + + + + + + + + Browse available integrations in the [Integrations section](/integrations/gallery/). + + +## Run and verify + +Now that you've added Aspire to your application, it's time to run it and see the orchestration in action. + + + +1. From your app root, run the application using the Aspire CLI: + + ```bash title="Run your application with Aspire" + aspire run + ``` + + The Aspire CLI will: + - Find your AppHost + - Build your app and its dependencies + - Launch all orchestrated services + - Start the Aspire dashboard + +2. The dashboard URL will appear in your terminal output: + + ```bash title="Example output" mark={4} + 🔍 Finding apphosts... + + Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 + + Logs: ~/.aspire/cli/logs/apphost-13024-2025-11-19-12-00-00.log + + Press CTRL+C to stop the apphost and exit. + ``` + + The CLI output also shows which AppHost Aspire found, such as `apphost.ts`. + +3. Open the dashboard in your browser using the provided URL. You'll see: + + - All your orchestrated resources and their status + - Real-time logs from each service + - Traces and metrics for observability + - Environment variables and configuration + +4. Verify that your services are running correctly by: + + - Checking the **Resources** page for service health + - Accessing your application endpoints + - Reviewing logs and traces in the dashboard + +5. Stop the application by pressing in your terminal. + + + + + +### Bonus content + +If you're currently using Docker Compose to orchestrate your services, Aspire can replace it while providing additional benefits: + + + +```yaml title="docker-compose.yml" showLineNumbers +services: + postgres: + image: postgres:latest + environment: + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=mydb + ports: + - "5432:5432" + + api: + build: ./api + ports: + - "8080:8080" + environment: + - DATABASE_URL=postgres://postgres:postgres@postgres:5432/mydb + depends_on: + - postgres + + web: + build: ./web + ports: + - "3000:3000" + environment: + - API_URL=http://api:8080 + depends_on: + - api +``` + + + +```typescript title="apphost.ts" showLineNumbers +import { createBuilder } from './.modules/aspire.js'; + +const builder = await createBuilder(); + +const db = (await builder.addPostgres("postgres")) + .addDatabase("mydb"); + +const api = await builder + .addNodeApp("api", "./api", "server.js") + .withNpm() + .withReference(db); + +await builder + .addViteApp("web", "./web") + .withExternalHttpEndpoints() + .withReference(api) + .waitFor(api); + +await builder.build().run(); +``` + + + + +The orchestration pattern stays the same: model the shared dependencies once, then connect services with `withReference`. + +**Key advantages of Aspire over Docker Compose:** + +- **Literally, less verbose** — Yet, more expressive and powerful. +- **No manual URL configuration** — Services discover each other automatically. +- **Code-based resource references** — Define service dependencies in code instead of duplicating them in YAML. +- **Built-in dashboard** — Observability without additional tools like Prometheus/Grafana. +- **Development and deployment** — Same orchestration code works locally and can generate Docker Compose or deploy anywhere. +- **Integration libraries** — Pre-built support for databases, caches, message queues with best practices. +- **JavaScript-friendly** — Works well with JavaScript and TypeScript apps plus containerized services. + + + +## Next steps + +Congratulations! You've successfully added Aspire to your existing application. Here are some recommended next steps: + +- **Add more integrations** — Explore [Aspire integrations](/integrations/gallery/) to simplify working with databases, caches, and message queues +- **Configure observability** — Enhance your application's telemetry: + + + - See [Standalone dashboard for Node.js](/dashboard/standalone-for-nodejs/) + + +- **Deploy your app** — Follow the [Deploy your first app](/get-started/deploy-first-app/) tutorial to deploy your Aspire application +- **Use the VS Code extension** — Run, debug, and manage integrations from within VS Code with the [Aspire extension](/get-started/aspire-vscode-extension/) +- **Explore the dashboard** — Learn more about the [Aspire dashboard](/dashboard/overview/) and its features +- **Learn about JavaScript support** — See [JavaScript support in Aspire](/whats-new/aspire-13/#javascript-as-a-first-class-citizen) diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx index d4a5ef9bc..82974be01 100644 --- a/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx @@ -1,1043 +1,36 @@ --- -title: Aspireify an existing app -description: Learn how to add Aspire orchestration to your existing application using aspire init. +title: "Aspireify an existing app" +description: "Choose an AppHost language for adding Aspire to an existing application." +prev: false +next: false --- -import { Aside, Steps, FileTree, Tabs, TabItem } from '@astrojs/starlight/components'; -import { Kbd } from 'starlight-kbd/components' +import { Aside, CardGrid, LinkCard } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; -import InstallPackage from '@components/InstallPackage.astro'; -import PivotSelector from '@components/PivotSelector.astro'; -import Pivot from '@components/Pivot.astro'; - - -This guide shows you how to add Aspire orchestration to an existing application, whether it's written in C#, Python, JavaScript, or a mix of these languages. Instead of starting from scratch, you'll use the `aspire init` command to incrementally adopt Aspire in your current project. +When you add Aspire to an existing application, the first choice is the language of the AppHost. Your services can stay in their current languages while the AppHost handles orchestration, service discovery, configuration injection, and local startup. - -:::note[Definition]{icon="approve-check-circle"} -**Aspireify** (verb): To transform an existing application into a distributed, observable, and orchestrated system by adding Aspire—no cape required, just a few commands! -::: - -## Why add Aspire to an existing app? - -As distributed applications grow, coordinating multiple services becomes a tangled web of configuration files, hard-coded URLs, and fragile startup scripts. You're juggling connection strings across environments, manually wiring service dependencies, and struggling to trace issues across your microservices. Development setup becomes a ritual of precision—start the database, then the cache, then service A before service B—and any misstep sends you back to square one. - -Aspire cuts through this complexity with a unified orchestration layer that treats your entire application as a cohesive system. Define your services and their relationships once in code ([the AppHost](/get-started/app-host/)), and Aspire handles service discovery, injects configuration automatically, and provides a dashboard with logs, traces, and metrics out of the box. Whether you're orchestrating C#, Python, or JavaScript services—or all three together—you get the same consistent experience from development through deployment. - -The best part? You can adopt Aspire incrementally. Start with orchestration, add observability when you're ready, integrate external services as needed. Your existing codebase stays largely unchanged, and you can reverse course if Aspire isn't the right fit. - -## Prerequisites - -Before you begin, ensure you have the following prerequisites installed based on your application's language: - -### Common requirements - -- [.NET SDK 10.0 or later](/get-started/prerequisites/) — Required for the Aspire AppHost, regardless of your application's language. -- [Aspire CLI installed](/get-started/install-cli/) — For orchestration and deployment commands. -- An existing application to add Aspire to. - -### Language-specific requirements - - - -**For C# applications:** - -- A solution with one or more .NET or ASP.NET Core projects (`.csproj`) -- Visual Studio 2022 17.13 or later, Visual Studio Code, or JetBrains Rider (optional) - -**Example project types:** -- ASP.NET Core Minimal API -- ASP.NET Core Razor Pages or Blazor applications -- Console applications -- Worker services -- gRPC services -- Azure Functions - - - - -**For Python applications:** - -- [Python 3.10 or later](https://www.python.org/downloads/) installed -- [uv](https://docs.astral.sh/uv/) (recommended) or pip for package management -- An existing Python application - -**Example application types:** -- FastAPI web applications -- Flask web applications -- Django applications -- Python scripts or worker processes -- Streamlit or other Python web frameworks - - - - -**For JavaScript/TypeScript applications:** - -- [Node.js 22 or later](https://nodejs.org/) installed -- npm, yarn, or pnpm for package management -- An existing JavaScript/TypeScript application - -**Example application types:** -- React, Vue, or Svelte applications (especially Vite-based) -- Node.js/Express APIs -- Next.js applications -- Angular applications -- TypeScript backend services - - - - - -## Overview of the process - -Adding Aspire to an existing application follows these key steps: - - - -1. **Initialize Aspire support** — Use `aspire init` to add the AppHost (orchestration layer) -2. **Add your applications** — Register C#, Python, and JavaScript applications in the AppHost -3. **Configure telemetry (optional)** — Add OpenTelemetry instrumentation for observability -4. **Add integrations (optional)** — Connect to databases, caches, and message queues -5. **Run and verify** — Test your application with Aspire orchestration - - - -## Initialize Aspire support - -The `aspire init` command is the starting point for adding Aspire to your existing application. It adds an AppHost that orchestrates your services while letting those services stay in their current languages. - - - -1. Navigate to your project directory: - - - ```bash title="Navigate to your solution directory" - cd /path/to/your-solution - ``` - - - ```bash title="Navigate to your project root" - cd /path/to/your-project - ``` - - - ```bash title="Navigate to your workspace root" - cd /path/to/your-workspace - ``` - - -2. Run `aspire init` to initialize Aspire support: - - - ```bash title="Initialize Aspire" - aspire init - ``` - - - ```bash title="Initialize Aspire with a TypeScript AppHost" - aspire init --language typescript - ``` - - - - - The `aspire init` command runs in **interactive mode** by default. It will: - - - - Detect your existing solution structure - - Create a project-based AppHost (an _AppHost_ project with `AppHost.cs`) - - Analyze your projects and suggest which ones to add to the orchestration - - Install necessary Aspire packages - - - - Detect your existing project structure - - Ask which AppHost language to create - - Create a file-based C# AppHost (`apphost.cs`) or a TypeScript AppHost (`apphost.ts`) - - Install the supporting packages for that AppHost - - - - Detect your existing workspace structure - - Create a TypeScript AppHost (`apphost.ts`) - - Add the generated AppHost SDK and config files - - Install the supporting Node.js dependencies for the AppHost - - - - For more details on the `aspire init` command and its options, see the [CLI reference: `aspire init`](/reference/cli/commands/aspire-init/). - - - - -### What does `aspire init` create? - - -After running `aspire init`, your solution will have a project-based AppHost: - - -- ExampleEcommerce.sln (updated) -- src/ - - **ExampleEcommerce.AppHost/** (new) orchestration project - - **ExampleEcommerce.AppHost.csproj** project file - - **AppHost.cs** orchestration code - - Api/ - - ExampleEcommerce.Api.csproj - - Program.cs - - Controllers/ - - Web/ - - ExampleEcommerce.Web.csproj - - Program.cs - - Pages/ - - OrderProcessor/ - - ExampleEcommerce.OrderProcessor.csproj - - Worker.cs - - -A typical e-commerce solution with a web frontend, API service, and background worker. - - -After running `aspire init`, your project will have a file-based AppHost: - - -- my-saas-app/ - - **apphost.cs** (new) orchestration code - - **apphost.run.json** (new) configuration - - api/ - - main.py - - routers/ - - models/ - - pyproject.toml - - frontend/ - - app.py - - templates/ - - static/ - - requirements.txt - - worker/ - - tasks.py - - celery_config.py - - requirements.txt - - -A typical SaaS application with FastAPI backend, Flask frontend, and Celery worker. - - -After running `aspire init --language typescript`, your project will have a TypeScript AppHost: - - -- my-store/ - - **apphost.ts** (new) orchestration code - - **.modules/** (new) generated SDK - - **aspire.config.json** (new) configuration - - **package.json** (new) AppHost dependencies - - **tsconfig.json** (new) TypeScript configuration - - packages/ - - api/ - - src/ - - server.js - - routes/ - - package.json - - web/ - - src/ - - App.tsx - - components/ - - package.json - - vite.config.ts - - admin/ - - src/ - - main.ts - - views/ - - package.json - - package.json (workspace root) - - -A typical monorepo with Node.js API, React storefront, and admin dashboard. - - - -The `AppHost.cs` file in your new AppHost project initially contains a minimal starter: - -```csharp title="AppHost.cs — Initial state after aspire init" -var builder = DistributedApplication.CreateBuilder(args); - -// TODO: Add resources here - -builder.Build().Run(); -``` - - - -The `apphost.cs` file initially contains a minimal starter: - -```csharp title="apphost.cs — Initial state after aspire init" -#:sdk Aspire.AppHost.Sdk@13.1.0 - -var builder = DistributedApplication.CreateBuilder(args); - -// TODO: Add resources here - -builder.Build().Run(); -``` - - - -The `apphost.ts` file initially contains a minimal starter: - -```typescript title="apphost.ts — Initial state after aspire init" -// Aspire TypeScript AppHost -// For more information, see: https://aspire.dev - -import { createBuilder } from './.modules/aspire.js'; - -const builder = await createBuilder(); - -// Add your resources here, for example: -// const redis = await builder.addContainer("cache", "redis:latest"); -// const postgres = await builder.addPostgres("db"); - -await builder.build().run(); -``` - - - -This is your starting point. In the next section, you'll add your applications and configure their relationships. - -## Add your applications to the AppHost - -Once you have an AppHost, you need to register your existing applications. First, install the appropriate hosting packages for your application types, then add your resources to the AppHost. - -### Install hosting packages - - - -For C# projects, if you're using project-based orchestration (`.csproj` files), no additional packages are needed. The base Aspire SDK includes support for `AddProject` (or `AddCSharpApp` for file-based apps). - - - - -For Python applications, install the Python hosting package: - - - -This package provides methods like `AddUvicornApp`, `AddPythonApp`, and `AddPythonModule`. - - - - -For JavaScript/TypeScript applications, add the JavaScript hosting integration to your AppHost: - -```bash title="Aspire CLI — Add JavaScript hosting integration" -aspire add javascript -``` - -This updates the generated AppHost SDK with methods like `addViteApp`, `addNodeApp`, and `addJavaScriptApp`. - - - -### Add C# project references - - - -Before you can use `AddProject` in your AppHost, the AppHost project must have a project reference to each C# project it orchestrates. These project references are what generate the `Projects.YourProject` marker types used by `AddProject`. - -If you used `aspire init`, it likely added these references automatically for the projects you selected. If you need to add more projects later, run the following commands from your AppHost project directory: - -```bash title=".NET CLI — Add project references to AppHost" -dotnet add reference ../Api/ExampleCommerce.Api.csproj -dotnet add reference ../Web/ExampleCommerce.Web.csproj -dotnet add reference ../OrderProcessor/ExampleCommerce.OrderProcessor.csproj -``` - -This updates the AppHost `.csproj` file with entries like: - -```xml title="ExampleCommerce.AppHost.csproj — Project references" - - - - - -``` - - - - -This step only applies to C# project-based AppHosts. Python and JavaScript file-based AppHosts don't use `.csproj` project references. - - - -### Model your resources in the AppHost - - -Now update your `AppHost.cs` file in the AppHost project to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. - - -Now update your `apphost.cs` file to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. - - -Now update your `apphost.ts` file to register your applications as resources. Resources are the building blocks of your distributed application—each service, container, or infrastructure resource becomes something Aspire can orchestrate. - - - - -For C# projects, use `AddProject` to reference your existing C# projects: - -```csharp title="AppHost.cs — Complete e-commerce example" -var builder = DistributedApplication.CreateBuilder(args); - -var api = builder.AddProject("api") - .WithHttpHealthCheck("/health"); - -var web = builder.AddProject("web") - .WithExternalHttpEndpoints() - .WithReference(api) - .WaitFor(api); - -var orderProcessor = builder.AddProject("orderprocessor") - .WithReference(api); - -builder.Build().Run(); -``` - -**Key methods:** -- `AddProject` - Adds a .NET project from your solution -- `WithHttpHealthCheck` - Monitors service health via HTTP endpoint -- `WithReference` - Enables service-to-service communication -- `WaitFor` - Ensures proper startup order - - - - -Aspire provides several methods for Python applications: - -```csharp title="apphost.cs — Complete SaaS example" -#:sdk Aspire.AppHost.Sdk@13.1.0 -#:package Aspire.Hosting.Python@13.1.0 - -var builder = DistributedApplication.CreateBuilder(args); - -// FastAPI backend -var api = builder.AddUvicornApp("api", "./api", "main:app") - .WithUv() - .WithHttpHealthCheck("/health"); - -// Flask frontend -var frontend = builder.AddUvicornApp("frontend", "./frontend", "app:app") - .WithUv() - .WithExternalHttpEndpoints() - .WithReference(api) - .WaitFor(api); - -// Celery worker -var worker = builder.AddPythonApp("worker", "./worker", "celery") - .WithUv() - .WithArgs("worker", "-A", "tasks") - .WithReference(api); - -builder.Build().Run(); -``` - -**Key methods:** -- `AddUvicornApp` - For FastAPI, Flask, and other ASGI/WSGI frameworks -- `AddPythonApp` - For standalone Python scripts -- `WithUv()` - Use uv for fast package management (recommended) -- `WithPip()` - Use traditional pip for package management - - - - -For JavaScript applications, use the appropriate method based on your application type: - -```typescript title="apphost.ts — Complete monorepo example" -import { createBuilder } from './.modules/aspire.js'; - -const builder = await createBuilder(); - -// Node.js API -const api = await builder - .addNodeApp("api", "./packages/api", "src/server.js") - .withNpm() - .withHttpHealthCheck({ path: "/health" }); - -// React storefront -const web = await builder - .addViteApp("web", "./packages/web") - .withExternalHttpEndpoints() - .withReference(api) - .waitFor(api); - -// Admin dashboard -const admin = await builder - .addViteApp("admin", "./packages/admin") - .withExternalHttpEndpoints() - .withReference(api) - .waitFor(api); - -await builder.build().run(); -``` - -**Key methods:** -- `addViteApp` - For Vite-based applications (React, Vue, Svelte) -- `addNodeApp` - For Node.js applications -- `addJavaScriptApp` - For generic JavaScript applications with npm/yarn/pnpm - - `withNpm()` / `withYarn()` / `withPnpm()` - Specify package manager -- `withRunScript` - Specify which npm script to run during development - -:::note[Passing arguments to scripts] -Unlike the deprecated `AddNpmApp` API in Aspire 9, the new JavaScript hosting methods (`addJavaScriptApp`, `addViteApp`, `addNodeApp`) do not support an `args` constructor parameter. You have two options to pass arguments to your scripts: - -**Option 1: Use `withArgs` to pass arguments directly** - -```typescript title="apphost.ts — Pass arguments using withArgs" -await builder - .addViteApp("frontend", "./frontend") - .withArgs(["--no-open"]); -``` - -**Option 2: Define custom scripts in `package.json` with arguments** - -```json title="package.json" -{ - "scripts": { - "dev": "vite", - "dev:no-open": "vite --no-open" - } -} -``` - -```typescript title="apphost.ts — Reference custom script" -await builder - .addViteApp("frontend", "./frontend") - .withRunScript("dev:no-open"); -``` - -Option 2 keeps all script configuration in `package.json`, making your scripts more discoverable and easier to run outside of Aspire (e.g., `npm run dev:no-open`). -::: - - - - -### Connect services - -The `WithReference` / `withReference` calls establish service dependencies and enable service discovery: - - - -```csharp title="AppHost.cs — Connect C# services" ".WithReference" -// Omitted for brevity... - -var api = builder.AddProject("api"); - -var web = builder.AddProject("web") - .WithReference(api); // Web can call API - -var worker = builder.AddProject("worker") - .WithReference(api); // Worker can call API - -// Omitted for brevity... -``` - - - - -```csharp title="apphost.cs — Connect Python services" ".WithReference" -// Omitted for brevity... - -var api = builder.AddUvicornApp("api", "../python-api", "main:app") - .WithUv(); - -var worker = builder.AddPythonApp("worker", "../python-worker", "worker.py") - .WithReference(api); // Worker gets API_HTTP and API_HTTPS env vars - -// Omitted for brevity... -``` - - - - -```typescript title="apphost.ts — Connect JavaScript services" ".withReference" -// Omitted for brevity... - -const api = await builder - .addNodeApp("api", "../node-api", "server.js") - .withNpm(); - -await builder - .addViteApp("frontend", "../react-frontend") - .withReference(api); // Frontend gets API_HTTP and API_HTTPS env vars - -// Omitted for brevity... -``` - - - -When you call `WithReference`, you're declaring a dependency between resources. Aspire handles the rest—automatically injecting configuration at runtime and during deployment so your services can communicate seamlessly, whether running locally or in production. - -## Add telemetry configuration (optional) - - - -ServiceDefaults provide a standardized way to add observability, resilience, and health checks to .NET services. This step is optional but recommended for production applications. - - - -1. During the `aspire init` process, you may be prompted to add ServiceDefaults. If you chose not to add it initially, you can add it later using the Aspire CLI or manually. - -2. To add ServiceDefaults to a project manually: - - ```bash title=".NET CLI — Add ServiceDefaults to your project" - dotnet new aspire-servicedefaults -n YourProject.ServiceDefaults - dotnet sln add YourProject.ServiceDefaults - dotnet add YourProject reference YourProject.ServiceDefaults - ``` - -3. Update your project's `Program.cs` to use ServiceDefaults: - - ```csharp title="Program.cs — Add ServiceDefaults" - var builder = WebApplication.CreateBuilder(args); - - // Add Aspire ServiceDefaults for observability and resilience - builder.AddServiceDefaults(); - - // ... your existing service configuration ... - - var app = builder.Build(); - - // Map Aspire ServiceDefaults endpoints - app.MapDefaultEndpoints(); - - // ... your existing middleware ... - - app.Run(); - ``` - - - - - For more information on ServiceDefaults, see [Service Defaults](/fundamentals/service-defaults/). - - - - - -Python applications can send telemetry to the Aspire dashboard using OpenTelemetry: - - - -1. Install OpenTelemetry packages in your Python application: - - ```bash title="Install OpenTelemetry packages" - uv add opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc - uv add opentelemetry-instrumentation-fastapi # For FastAPI - # Or for Flask: - # uv add opentelemetry-instrumentation-flask - ``` - -2. Configure OpenTelemetry in your Python application: - - ```python title="Python — Configure OpenTelemetry" - import os - from opentelemetry import trace, metrics - from opentelemetry.sdk.trace import TracerProvider - from opentelemetry.sdk.metrics import MeterProvider - from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter - from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter - from opentelemetry.sdk.resources import Resource - from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor - - # Get OTLP endpoint from environment (injected by Aspire) - otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT") - - # Configure tracing and metrics - resource = Resource.create({"service.name": "api"}) - trace.set_tracer_provider(TracerProvider(resource=resource)) - metrics.set_meter_provider(MeterProvider(resource=resource)) - - # Instrument your FastAPI app - FastAPIInstrumentor.instrument_app(app) - ``` - - - - - - -JavaScript/Node.js applications can also send telemetry using OpenTelemetry: - - - -1. Install OpenTelemetry packages: - - ```bash title="Install OpenTelemetry packages" - npm install @opentelemetry/api @opentelemetry/sdk-node \ - @opentelemetry/auto-instrumentations-node \ - @opentelemetry/exporter-trace-otlp-grpc \ - @opentelemetry/exporter-metrics-otlp-grpc - ``` - -2. Create a telemetry configuration file: - - ```javascript title="JavaScript — telemetry.js" - const { NodeSDK } = require('@opentelemetry/sdk-node'); - const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); - const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); - const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc'); - const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics'); - const { resourceFromAttributes } = require('@opentelemetry/resources'); - const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions'); - - const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317'; - - // Create resource with service name - const resource = resourceFromAttributes({ - [ATTR_SERVICE_NAME]: 'frontend', - }); - - const sdk = new NodeSDK({ - resource: resource, - traceExporter: new OTLPTraceExporter({ url: otlpEndpoint }), - metricReader: new PeriodicExportingMetricReader({ - exporter: new OTLPMetricExporter({ url: otlpEndpoint }) - }), - instrumentations: [getNodeAutoInstrumentations()] - }); - - sdk.start(); - ``` - -3. Import the telemetry configuration at the top of your application entry point: - - ```javascript title="JavaScript — app.js" - // This must be first! - require('./telemetry'); - - const express = require('express'); - // ... rest of your app - ``` - - - - - -## Add integrations (optional) - -Aspire provides integration libraries that simplify working with common services like Redis, PostgreSQL, RabbitMQ, and more. These integrations handle configuration, health checks, and telemetry automatically. - -When you add a hosting integration (like Redis) to your AppHost and reference it from a dependent resource, Aspire automatically injects the necessary configuration. This includes connection strings, URLs, environment variables, and other service-specific settings—eliminating manual connection string management across your services. - - - -1. Identify which services in your application could benefit from Aspire integrations. Common candidates include: - - - Databases (PostgreSQL, SQL Server, MongoDB) - - Caching (Redis, Valkey) - - Messaging (RabbitMQ, Azure Service Bus, Kafka) - - Storage (Azure Blob Storage, AWS S3) - -2. Use the `aspire add` command to add integration packages to your AppHost: - - ```bash title="Add a Redis integration" - aspire add redis - ``` - - This command adds the necessary AppHost dependencies and helps you configure the integration. - -3. Update your AppHost to reference the integration and share it across all your services: - - - - ```csharp title="apphost.cs — Add Redis integration for multiple services" - var builder = DistributedApplication.CreateBuilder(args); - - // Add Redis resource - var cache = builder.AddRedis("cache"); - - // Share Redis with .NET API - var api = builder.AddProject("api") - .WithReference(cache) - .WithHttpHealthCheck("/health"); - - // Share Redis with Python worker - var pythonWorker = builder.AddPythonApp("worker", "../python-worker", "worker.py") - .WithReference(cache); // Python gets CACHE_HOST, CACHE_PORT env vars - - // Share Redis with Node.js service - var nodeService = builder.AddNodeApp("service", "../node-service", "index.js") - .WithReference(cache); // Node.js gets CACHE_HOST, CACHE_PORT env vars - - builder.Build().Run(); - ``` - - - - - ```typescript title="apphost.ts — Add Redis integration for multiple services" - import { createBuilder } from './.modules/aspire.js'; - - const builder = await createBuilder(); - - const cache = await builder.addRedis("cache"); - - await builder - .addNodeApp("api", "../node-api", "server.js") - .withNpm() - .withReference(cache); - - await builder - .addNodeApp("worker", "../node-worker", "worker.js") - .withNpm() - .withReference(cache); - - await builder.build().run(); - ``` - - - -4. Configure the integration in each language: - - - - ```bash title="Add Redis client to .NET project" - dotnet add YourApi package Aspire.StackExchange.Redis - ``` - - ```csharp title="Program.cs — Configure Redis client" - var builder = WebApplication.CreateBuilder(args); - builder.AddRedisClient("cache"); - ``` - - - - - ```bash title="Add Redis client to Python project" - uv add redis - ``` - - ```python title="Python — Configure Redis client" - import os - import redis - - # Aspire injects CACHE_HOST and CACHE_PORT - redis_client = redis.Redis( - host=os.getenv("CACHE_HOST"), - port=int(os.getenv("CACHE_PORT")), - decode_responses=True - ) - ``` - - - - - ```bash title="Add Redis client to Node.js project" - npm install redis - ``` - - ```javascript title="JavaScript — Configure Redis client" - const redis = require('redis'); - - // Aspire injects CACHE_HOST and CACHE_PORT - const client = redis.createClient({ - socket: { - host: process.env.CACHE_HOST, - port: process.env.CACHE_PORT - } - }); - ``` + + + + - +## Before you begin - +Before following either path, make sure you've completed the [prerequisites](/get-started/prerequisites/) and [installed the Aspire CLI](/get-started/install-cli/). - Browse available integrations in the [Integrations section](/integrations/gallery/). +For command details and language options, see the [CLI reference: `aspire init`](/reference/cli/commands/aspire-init/). - -## Run and verify - -Now that you've added Aspire to your application, it's time to run it and see the orchestration in action. - - - -1. From your app root, run the application using the Aspire CLI: - - ```bash title="Run your application with Aspire" - aspire run - ``` - - The Aspire CLI will: - - Find your AppHost - - Build your app and its dependencies - - Launch all orchestrated services - - Start the Aspire dashboard - -2. The dashboard URL will appear in your terminal output: - - ```bash title="Example output" mark={4} - 🔍 Finding apphosts... - - Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 - - Logs: ~/.aspire/cli/logs/apphost-13024-2025-11-19-12-00-00.log - - Press CTRL+C to stop the apphost and exit. - ``` - - The CLI output also shows which AppHost Aspire found, such as `apphost.ts`, `apphost.cs`, or an `AppHost.csproj` file. - -3. Open the dashboard in your browser using the provided URL. You'll see: - - - All your orchestrated resources and their status - - Real-time logs from each service - - Traces and metrics for observability - - Environment variables and configuration - -4. Verify that your services are running correctly by: - - - Checking the **Resources** page for service health - - Accessing your application endpoints - - Reviewing logs and traces in the dashboard - -5. Stop the application by pressing in your terminal. - - - - - -### Bonus content - -If you're currently using Docker Compose to orchestrate your services, Aspire can replace it while providing additional benefits: - - - -```yaml title="docker-compose.yml" showLineNumbers -services: - postgres: - image: postgres:latest - environment: - - POSTGRES_PASSWORD=postgres - - POSTGRES_DB=mydb - ports: - - "5432:5432" - - api: - build: ./api - ports: - - "8080:8080" - environment: - - DATABASE_URL=postgres://postgres:postgres@postgres:5432/mydb - depends_on: - - postgres - - web: - build: ./web - ports: - - "3000:3000" - environment: - - API_URL=http://api:8080 - depends_on: - - api -``` - - - -```csharp title="apphost.cs" showLineNumbers -var builder = DistributedApplication.CreateBuilder(args); - -var db = builder.AddPostgres("postgres") - .AddDatabase("mydb"); - -var api = builder.AddProject("api") - .WithReference(db); - -var web = builder.AddProject("web") - .WithExternalHttpEndpoints() - .WithReference(api) - .WaitFor(api); - -builder.Build().Run(); -``` - - -```typescript title="apphost.ts" showLineNumbers -import { createBuilder } from './.modules/aspire.js'; - -const builder = await createBuilder(); - -const db = (await builder.addPostgres("postgres")) - .addDatabase("mydb"); - -const api = await builder - .addNodeApp("api", "./api", "server.js") - .withNpm() - .withReference(db); - -await builder - .addViteApp("web", "./web") - .withExternalHttpEndpoints() - .withReference(api) - .waitFor(api); - -await builder.build().run(); -``` - - - - -The exact AppHost methods differ by language and service type, but the orchestration pattern is the same: model the shared dependencies once, then connect services with `WithReference` / `withReference`. - -**Key advantages of Aspire over Docker Compose:** - -- **Literally, less verbose** — Yet, more expressive and powerful. -- **No manual URL configuration** — Services discover each other automatically. -- **Code-based resource references** — Define service dependencies in code instead of duplicating them in YAML. -- **Built-in dashboard** — Observability without additional tools like Prometheus/Grafana. -- **Development and deployment** — Same orchestration code works locally and can generate Docker Compose or deploy anywhere. -- **Integration libraries** — Pre-built support for databases, caches, message queues with best practices. -- **Language-agnostic** — Works with C#, Python, JavaScript, many more, and containerized services. - - - -## Next steps - -Congratulations! You've successfully added Aspire to your existing application. Here are some recommended next steps: - -- **Add more integrations** — Explore [Aspire integrations](/integrations/gallery/) to simplify working with databases, caches, and message queues -- **Configure observability** — Enhance your application's telemetry: - - - Learn about [Service Defaults](/fundamentals/service-defaults/) - - - - See [Standalone dashboard for Python](/dashboard/standalone-for-python/) - - - - See [Standalone dashboard for Node.js](/dashboard/standalone-for-nodejs/) - -- **Deploy your app** — Follow the [Deploy your first app](/get-started/deploy-first-app/) tutorial to deploy your Aspire application -- **Use the VS Code extension** — Run, debug, and manage integrations from within VS Code with the [Aspire extension](/get-started/aspire-vscode-extension/) -- **Explore the dashboard** — Learn more about the [Aspire dashboard](/dashboard/overview/) and its features -- **Learn about multi-language features**: - - [Python support in Aspire](/whats-new/aspire-13/#python-as-a-first-class-citizen) - - [JavaScript support in Aspire](/whats-new/aspire-13/#javascript-as-a-first-class-citizen) diff --git a/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx b/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx new file mode 100644 index 000000000..4c79d453c --- /dev/null +++ b/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx @@ -0,0 +1,373 @@ +--- +title: "Build your first Aspire app with a C# AppHost" +description: "Learn how to build your first Aspire solution using starter templates that generate a C# AppHost." +prev: false +next: false +--- + +import { Aside, Steps, FileTree } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components' +import LearnMore from '@components/LearnMore.astro'; +import PivotSelector from '@components/PivotSelector.astro'; +import Pivot from '@components/Pivot.astro'; +import ThemeImage from '@components/ThemeImage.astro'; + +import csharpDashboardLight from '@assets/get-started/csharp-aspire-dashboard-light.png'; +import csharpDashboardDark from '@assets/get-started/csharp-aspire-dashboard-dark.png'; +import pythonDashboardLight from '@assets/get-started/python-aspire-dashboard-light.png'; +import pythonDashboardDark from '@assets/get-started/python-aspire-dashboard-dark.png'; + + +This quickstart uses starter templates that generate a C# AppHost. Choose the app stack you want to start from, then create the solution, review the generated AppHost, and run it locally with Aspire. + + + + +This starter template uses modern C#: + +- [Minimal APIs](https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis) for lightweight HTTP APIs +- [Blazor](https://learn.microsoft.com/aspnet/core/blazor) for interactive web UIs using C# +- [Service defaults](/fundamentals/service-defaults/) for shared configuration of observability and resilience + +The following diagram shows the architecture of the sample app you're creating: + +```mermaid +architecture-beta + + service api(logos:dotnet)[API service] + service frontend(aspire:blazor)[Blazor front end] + + frontend:L --> R:api +``` + + + +This starter template combines a modern Python and JavaScript stack: + +- [FastAPI](https://fastapi.tiangolo.com/) for building APIs with Python +- [Uv](https://docs.astral.sh/uv/) for Python package installation and environment management +- [React](https://react.dev/) for building user interfaces with JavaScript + +The following diagram shows the architecture of the sample app you're creating: + +```mermaid +architecture-beta + service api(logos:fastapi)[API service] + service frontend(logos:react)[React front end] + + frontend:L --> R:api +``` + + + + +## Create a new app + +To create your first Aspire application, use the [Aspire CLI](/get-started/install-cli/) to generate a new solution from a _starter_ template. These template include multiple projects, such as an API service, a web frontend, and an [Aspire AppHost](/get-started/app-host/). + + + +1. Create a new Aspire solution from a template: + + + ```bash title="Create a new aspire solution" + aspire new aspire-starter -n AspireApp -o AspireApp + ``` + + + + ```bash title="Create a new aspire solution" + aspire new aspire-py-starter -n aspire-app -o aspire-app + ``` + + + + + The template provides several projects, including an API service, web frontend, and AppHost. + + + + + For further CLI reference, see [`aspire new`](/reference/cli/commands/aspire-new/) command information. + + + If prompted for additional selections, use the and keys to navigate the options. Press to confirm your selection. + + + + + +## Review the template code + + + +1. Examine the created template structure. The Aspire CLI creates a new folder with the name you provided in the current directory. This folder contains the solution file and several projects, including: + + + + - AspireApp.sln + - AspireApp.ApiService mock weather data API + - Properties/ + - appsettings.Development.json + - appsettings.json + - AspireApp.ApiService.csproj + - Program.cs + - **AspireApp.AppHost** dev-time orchestrator + - Properties/ + - appsettings.Development.json + - appsettings.json + - AspireApp.AppHost.csproj + - AppHost.cs + - AspireApp.ServiceDefaults + - Extensions.cs + - AspireApp.ServiceDefaults.csproj + - AspireApp.Web ASP.NET Core Blazor front end + - Properties/ + - wwwroot/ + - appsettings.Development.json + - appsettings.json + - AspireApp.Web.csproj + - Program.cs + - WeatherApiClient.cs + + + + + - aspire-app/ + - app/ FastAPI mock weather data API + - .dockerignore + - .python-version + - main.py + - pyproject.toml + - telemetry.py + - frontend/ Vite + React web front end + - .dockerignore + - public/ + - Aspire.png + - github.svg + - src/ + - App.css + - App.tsx + - index.css + - main.tsx + - vite-env.d.ts + - .gitignore + - eslint.config.js + - index.html + - package-lock.json + - package.json + - tsconfig.app.json + - tsconfig.json + - tsconfig.node.json + - vite.config.ts + - **apphost.cs** dev-time orchestrator + - apphost.run.json + - NuGet.config + + + + + This solution structure is based on the Aspire templates. If they're not installed already, the CLI will install them for you. + +1. Explore the AppHost code that orchestrates your app. + + The [AppHost](/get-started/app-host/) is the heart of your Aspire application—it defines which services run, how they connect, and in what order they start. Let's look at the generated code: + + + ```csharp title="C# — AppHost.cs project-based orchestrator" + var builder = DistributedApplication.CreateBuilder(args); + + var apiService = builder.AddProject("apiservice") + .WithHttpHealthCheck("/health"); + + builder.AddProject("webfrontend") + .WithExternalHttpEndpoints() + .WithHttpHealthCheck("/health") + .WithReference(apiService) + .WaitFor(apiService); + + builder.Build().Run(); + ``` + + _What's happening here?_ + + - `CreateBuilder` creates the distributed application builder + - `AddProject` registers your API service and web frontend + - `WithReference` connects services—it injects the API's URL as an environment variable and sets up service discovery so you can use service names instead of hardcoded URLs + - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors from race conditions + - `WithHttpHealthCheck` monitors service health + + + + ```csharp title="C# — apphost.cs file-based orchestrator" + #:sdk Aspire.AppHost.Sdk@13.1.0 + #:package Aspire.Hosting.JavaScript@13.1.0 + #:package Aspire.Hosting.Python@13.1.0 + + var builder = DistributedApplication.CreateBuilder(args); + + var app = builder.AddUvicornApp("app", "./app", "main:app") + .WithUv() + .WithExternalHttpEndpoints() + .WithHttpHealthCheck("/health"); + + var frontend = builder.AddViteApp("frontend", "./frontend") + .WithReference(app) + .WaitFor(app); + + app.PublishWithContainerFiles(frontend, "./static"); + + builder.Build().Run(); + ``` + + _What's happening here?_ + + - `AddUvicornApp` adds a Uvicorn-based Python app + - `AddUv` adds a Uv environment setup task: `uv sync` + - `AddViteApp` registers your React frontend + - `WithReference` connects the frontend to the API—it injects the API's URL and sets up service discovery + - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors + - `PublishWithContainerFiles` bundles the frontend for production deployment + + + + + + + + +## Run the app + + + +1. Change to the _output_ directory: + + + ```bash title="Change directories" + cd ./AspireApp + ``` + + + + + ```bash title="Change directories" + cd ./aspire-app + ``` + + + +1. Call `aspire run` to start dev-time orchestration: + + ```bash title="Run dev-time orchestration" + aspire run + ``` + + When you run this command, the Aspire CLI: + + - Automatically finds the AppHost + - Builds your solution + - Launches dev-time orchestration + + Once the dashboard is ready, its URL (with a login token—highlighted in the example output below) appears in your terminal. The dashboard provides a live, real-time view of your running resources and their current states. + + + ```bash title="Example output" mark={8} + 🔍 Finding apphosts... + AspireApp.AppHost/AspireApp.AppHost.csproj + + 🗄 Created settings file at '.aspire/settings.json'. + + AppHost: AspireApp.AppHost/AspireApp.AppHost.csproj + + Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 + + Logs: %USERPROFILE%/.aspire/cli/logs/apphost-13024-2025-10-31-19-40-58.log + + Press CTRL+C to stop the apphost and exit. + ``` + + + + + ```bash title="Example output" mark={8} + 🔍 Finding apphosts... + apphost.cs + + 🗄 Created settings file at '.aspire/settings.json'. + + AppHost: apphost.cs + + Dashboard: https://localhost:17213/login?t=2b4a2ebc362b7fef9b5ccf73e702647b + + Logs: $HOME/.aspire/cli/logs/apphost-27732-2025-10-31-19-21-27.log + + Press CTRL+C to stop the apphost and exit. + ``` + + + + + For further CLI reference, see [`aspire run`](/reference/cli/commands/aspire-run/) command information. + + +1. Explore the running distributed application. From the dashboard, open the `HTTPS` endpoint from each resource. + + + + + + + + + + + To learn more, see [Aspire dashboard overview](/dashboard/overview/). + + + + +## Stop the app + + + +1. Stop the AppHost and close the dashboard by pressing in your terminal. + + ```bash title="Stop dev-time orchestration" + 🛑 Stopping Aspire. + ``` + + **🥳 Congratulations! You've created your first Aspire app.** + + + + +You might be eager to deploy this app next—and we'll show you how Aspire handles that—but you're probably also wondering: "How do I _test_ all this?" Great question! Aspire doesn't just orchestrate locally and deploy, it also helps you test service and resource integrations too. Ready to dive in? [Write your first test](/testing/write-your-first-test/) 💜 + + +## See also + +- Having trouble? Check out our [Troubleshooting guide](/get-started/troubleshooting/) for solutions to common problems. +- Prefer a GUI? The [Aspire VS Code extension](/get-started/aspire-vscode-extension/) lets you create, run, and debug Aspire apps from VS Code. diff --git a/src/frontend/src/content/docs/get-started/first-app-typescript-apphost.mdx b/src/frontend/src/content/docs/get-started/first-app-typescript-apphost.mdx new file mode 100644 index 000000000..cdba0e145 --- /dev/null +++ b/src/frontend/src/content/docs/get-started/first-app-typescript-apphost.mdx @@ -0,0 +1,262 @@ +--- +title: "Build your first Aspire app with a TypeScript AppHost" +description: "Learn how to build your first Aspire solution using the JavaScript starter template and a TypeScript AppHost." +prev: false +next: false +--- + +import { Aside, Steps, FileTree } from '@astrojs/starlight/components'; +import { Kbd } from 'starlight-kbd/components' +import LearnMore from '@components/LearnMore.astro'; +import ThemeImage from '@components/ThemeImage.astro'; + +import javascriptDashboardLight from '@assets/get-started/javascript-aspire-dashboard-light.png'; +import javascriptDashboardDark from '@assets/get-started/javascript-aspire-dashboard-dark.png'; + + +This quickstart uses the JavaScript starter template, which generates a TypeScript AppHost in `apphost.ts`. You'll create the solution, review the generated TypeScript AppHost, and run it locally with Aspire. + + + +This starter template combines a modern JavaScript stack: + +- [Express](https://expressjs.com/) for building APIs with Node.js +- [React](https://react.dev/) for building user interfaces with JavaScript +- [TypeScript](https://www.typescriptlang.org/) for type-safe development across the entire stack + +The following diagram shows the architecture of the sample app you're creating: + +```mermaid +architecture-beta + service api(logos:nodejs-icon)[API service] + service frontend(logos:react)[React front end] + + frontend:L --> R:api +``` + + +## Create a new app + +To create your first Aspire application, use the [Aspire CLI](/get-started/install-cli/) to generate a new solution from a _starter_ template. These template include multiple projects, such as an API service, a web frontend, and an [Aspire AppHost](/get-started/app-host/). + + + +1. Create a new Aspire solution from a template: + + + + ```bash title="Create a new aspire solution" + aspire new aspire-ts-starter -n aspire-app -o aspire-app + ``` + + + + + The template provides several projects, including an API service, web frontend, and AppHost. + + + + + For further CLI reference, see [`aspire new`](/reference/cli/commands/aspire-new/) command information. + + + If prompted for additional selections, use the and keys to navigate the options. Press to confirm your selection. + + + + + + + + +## Review the template code + + + +1. Examine the created template structure. The Aspire CLI creates a new folder with the name you provided in the current directory. This folder contains the solution file and several projects, including: + + + + + - aspire-app/ + - api/ Express mock weather data API + - src/ + - index.ts + - instrumentation.ts + - package.json + - tsconfig.json + - frontend/ Vite + React web front end + - public/ + - Aspire.png + - github.svg + - src/ + - App.css + - App.tsx + - index.css + - main.tsx + - vite-env.d.ts + - .dockerignore + - eslint.config.js + - index.html + - package.json + - tsconfig.json + - vite.config.ts + - **apphost.ts** dev-time orchestrator + - aspire.config.json + - package.json + + + + + This solution structure is based on the Aspire templates. If they're not installed already, the CLI will install them for you. + +1. Explore the AppHost code that orchestrates your app. + + The [AppHost](/get-started/app-host/) is the heart of your Aspire application—it defines which services run, how they connect, and in what order they start. Let's look at the generated code: + + + + ```typescript title="TypeScript — apphost.ts" + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + + // Run the Express API and expose its HTTP endpoint externally. + const app = await builder + .addNodeApp("app", "./api", "src/index.ts") + .withHttpEndpoint({ env: "PORT" }) + .withExternalHttpEndpoints(); + + // Run the Vite frontend after the API and inject the API URL for local proxying. + const frontend = await builder + .addViteApp("frontend", "./frontend") + .withReference(app) + .waitFor(app); + + // Bundle the frontend build output into the API container for publish/deploy. + await app.publishWithContainerFiles(frontend, "./static"); + + await builder.build().run(); + ``` + + _What's happening here?_ + + - `createBuilder` creates the distributed application builder + - `addNodeApp` adds a Node.js application (the Express API) + - `addViteApp` registers your React frontend + - `withReference` connects the frontend to the API—it injects the API's URL and sets up service discovery + - `waitFor` ensures the API is running before starting the frontend, preventing connection errors + - `publishWithContainerFiles` bundles the frontend for production deployment + + + This template uses a TypeScript AppHost. To learn more about how multi-language AppHosts work, see [Multi-language architecture](/architecture/multi-language-architecture/). + + + + + + + + + +## Run the app + + + +1. Change to the _output_ directory: + + + + ```bash title="Change directories" + cd ./aspire-app + ``` + + + + +1. Call `aspire run` to start dev-time orchestration: + + ```bash title="Run dev-time orchestration" + aspire run + ``` + + When you run this command, the Aspire CLI: + + - Automatically finds the AppHost + - Builds your solution + - Launches dev-time orchestration + + Once the dashboard is ready, its URL (with a login token—highlighted in the example output below) appears in your terminal. The dashboard provides a live, real-time view of your running resources and their current states. + + + + + ```bash title="Example output" mark={6} + 🔍 Finding apphosts... + apphost.ts + + AppHost: apphost.ts + + Dashboard: https://localhost:17174/login?t=afb274c630f48b1c4ddfe139011c1cb7 + + Logs: %USERPROFILE%/.aspire/logs/cli_20260318T134627_f31ad598.log + + Press CTRL+C to stop the apphost and exit. + ``` + + + + + For further CLI reference, see [`aspire run`](/reference/cli/commands/aspire-run/) command information. + + +1. Explore the running distributed application. From the dashboard, open the `HTTPS` endpoint from each resource. + + + + + + + + + To learn more, see [Aspire dashboard overview](/dashboard/overview/). + + + + +## Stop the app + + + +1. Stop the AppHost and close the dashboard by pressing in your terminal. + + ```bash title="Stop dev-time orchestration" + 🛑 Stopping Aspire. + ``` + + **🥳 Congratulations! You've created your first Aspire app.** + + + + +You might be eager to deploy this app next—and we'll show you how Aspire handles that—but you're probably also wondering: "How do I _test_ all this?" Great question! Aspire doesn't just orchestrate locally and deploy, it also helps you test service and resource integrations too. Ready to dive in? [Write your first test](/testing/write-your-first-test/) 💜 + + +## See also + +- Having trouble? Check out our [Troubleshooting guide](/get-started/troubleshooting/) for solutions to common problems. +- Prefer a GUI? The [Aspire VS Code extension](/get-started/aspire-vscode-extension/) lets you create, run, and debug Aspire apps from VS Code. diff --git a/src/frontend/src/content/docs/get-started/first-app.mdx b/src/frontend/src/content/docs/get-started/first-app.mdx index 3dc50020c..62a748ca2 100644 --- a/src/frontend/src/content/docs/get-started/first-app.mdx +++ b/src/frontend/src/content/docs/get-started/first-app.mdx @@ -1,499 +1,36 @@ --- -title: Build your first Aspire app -description: Learn how to build your first Aspire solution using the Aspire starter templates for C#, Python, and JavaScript. +title: "Build your first Aspire app" +description: "Choose an AppHost language for your first Aspire app and follow the matching quickstart." +prev: false +next: false --- -import { Aside, CardGrid, LinkCard, Steps, Tabs, TabItem, Icon, FileTree } from '@astrojs/starlight/components'; -import { Kbd } from 'starlight-kbd/components' +import { Aside, CardGrid, LinkCard } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; -import PivotSelector from '@components/PivotSelector.astro'; -import Pivot from '@components/Pivot.astro'; -import ThemeImage from '@components/ThemeImage.astro'; -import pythonIcon from "@assets/icons/python.svg"; -import reactIcon from "@assets/icons/react-icon.svg"; -import uvIcon from "@assets/icons/uv-icon.svg"; -import fastApiIcon from "@assets/icons/fastapi-icon.svg"; +Build your first Aspire app by first choosing the AppHost language you want to work in. The AppHost is the code-first orchestrator for your solution, so this choice determines whether your walkthrough uses `AppHost.cs` / `apphost.cs` or `apphost.ts`. - - -In this quickstart, you'll create and run your first Aspire application using the Aspire CLI. Before you begin, make sure you've completed the [prerequisites](/get-started/prerequisites/) and [installed the Aspire CLI](/get-started/install-cli/). This guide walks you through generating a new Aspire solution from a template, running the application locally with Aspire's dev-time orchestration, and exploring the Aspire dashboard. After completing this quickstart, consider [deploying your apps](/get-started/deploy-first-app/). - - - -This starter template uses modern C#: - -- [Minimal APIs](https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis) for lightweight HTTP APIs -- [Blazor](https://learn.microsoft.com/aspnet/core/blazor) for interactive web UIs using C# -- [Service defaults](/fundamentals/service-defaults/) for shared configuration of observability and resilience - -The following diagram shows the architecture of the sample app you're creating: - -```mermaid -architecture-beta - - service api(logos:dotnet)[API service] - service frontend(aspire:blazor)[Blazor front end] - - frontend:L --> R:api -``` - - - - -This starter template combines a modern Python and JavaScript stack: - -- [FastAPI](https://fastapi.tiangolo.com/) for building APIs with Python -- [Uv](https://docs.astral.sh/uv/) for Python package installation and environment management -- [React](https://react.dev/) for building user interfaces with JavaScript - -The following diagram shows the architecture of the sample app you're creating: - -```mermaid -architecture-beta - service api(logos:fastapi)[API service] - service frontend(logos:react)[React front end] - - frontend:L --> R:api -``` - - - - -This starter template combines a modern JavaScript stack: - -- [Express](https://expressjs.com/) for building APIs with Node.js -- [React](https://react.dev/) for building user interfaces with JavaScript -- [TypeScript](https://www.typescriptlang.org/) for type-safe development across the entire stack - -The following diagram shows the architecture of the sample app you're creating: - -```mermaid -architecture-beta - service api(logos:nodejs-icon)[API service] - service frontend(logos:react)[React front end] - - frontend:L --> R:api -``` - - - -## Create a new app - -To create your first Aspire application, use the [Aspire CLI](/get-started/install-cli/) to generate a new solution from a _starter_ template. These template include multiple projects, such as an API service, a web frontend, and an [Aspire AppHost](/get-started/app-host/). - - - -1. Create a new Aspire solution from a template: - - - - ```bash title="Create a new aspire solution" - aspire new aspire-starter -n AspireApp -o AspireApp - ``` - - - - - ```bash title="Create a new aspire solution" - aspire new aspire-py-starter -n aspire-app -o aspire-app - ``` - - - - - ```bash title="Create a new aspire solution" - aspire new aspire-ts-starter -n aspire-app -o aspire-app - ``` - - - - The template provides several projects, including an API service, web frontend, and AppHost. - - - - - For further CLI reference, see [`aspire new`](/reference/cli/commands/aspire-new/) command information. - - - If prompted for additional selections, use the and keys to navigate the options. Press to confirm your selection. - - - - - - - - - -## Review the template code - - - -1. Examine the created template structure. The Aspire CLI creates a new folder with the name you provided in the current directory. This folder contains the solution file and several projects, including: - - - - - AspireApp.sln - - AspireApp.ApiService mock weather data API - - Properties/ - - appsettings.Development.json - - appsettings.json - - AspireApp.ApiService.csproj - - Program.cs - - **AspireApp.AppHost** dev-time orchestrator - - Properties/ - - appsettings.Development.json - - appsettings.json - - AspireApp.AppHost.csproj - - AppHost.cs - - AspireApp.ServiceDefaults - - Extensions.cs - - AspireApp.ServiceDefaults.csproj - - AspireApp.Web ASP.NET Core Blazor front end - - Properties/ - - wwwroot/ - - appsettings.Development.json - - appsettings.json - - AspireApp.Web.csproj - - Program.cs - - WeatherApiClient.cs - - - - - - aspire-app/ - - app/ FastAPI mock weather data API - - .dockerignore - - .python-version - - main.py - - pyproject.toml - - telemetry.py - - frontend/ Vite + React web front end - - .dockerignore - - public/ - - Aspire.png - - github.svg - - src/ - - App.css - - App.tsx - - index.css - - main.tsx - - vite-env.d.ts - - .gitignore - - eslint.config.js - - index.html - - package-lock.json - - package.json - - tsconfig.app.json - - tsconfig.json - - tsconfig.node.json - - vite.config.ts - - **apphost.cs** dev-time orchestrator - - apphost.run.json - - NuGet.config - - - - - - aspire-app/ - - api/ Express mock weather data API - - src/ - - index.ts - - instrumentation.ts - - package.json - - tsconfig.json - - frontend/ Vite + React web front end - - public/ - - Aspire.png - - github.svg - - src/ - - App.css - - App.tsx - - index.css - - main.tsx - - vite-env.d.ts - - .dockerignore - - eslint.config.js - - index.html - - package.json - - tsconfig.json - - vite.config.ts - - **apphost.ts** dev-time orchestrator - - aspire.config.json - - package.json - - - - This solution structure is based on the Aspire templates. If they're not installed already, the CLI will install them for you. - -1. Explore the AppHost code that orchestrates your app. - - The [AppHost](/get-started/app-host/) is the heart of your Aspire application—it defines which services run, how they connect, and in what order they start. Let's look at the generated code: - - - ```csharp title="C# — AppHost.cs project-based orchestrator" - var builder = DistributedApplication.CreateBuilder(args); - - var apiService = builder.AddProject("apiservice") - .WithHttpHealthCheck("/health"); - - builder.AddProject("webfrontend") - .WithExternalHttpEndpoints() - .WithHttpHealthCheck("/health") - .WithReference(apiService) - .WaitFor(apiService); - - builder.Build().Run(); - ``` - - _What's happening here?_ - - - `CreateBuilder` creates the distributed application builder - - `AddProject` registers your API service and web frontend - - `WithReference` connects services—it injects the API's URL as an environment variable and sets up service discovery so you can use service names instead of hardcoded URLs - - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors from race conditions - - `WithHttpHealthCheck` monitors service health - - - - ```csharp title="C# — apphost.cs file-based orchestrator" - #:sdk Aspire.AppHost.Sdk@13.1.0 - #:package Aspire.Hosting.JavaScript@13.1.0 - #:package Aspire.Hosting.Python@13.1.0 - - var builder = DistributedApplication.CreateBuilder(args); + - var app = builder.AddUvicornApp("app", "./app", "main:app") - .WithUv() - .WithExternalHttpEndpoints() - .WithHttpHealthCheck("/health"); - - var frontend = builder.AddViteApp("frontend", "./frontend") - .WithReference(app) - .WaitFor(app); - - app.PublishWithContainerFiles(frontend, "./static"); - - builder.Build().Run(); - ``` - - _What's happening here?_ - - - `AddUvicornApp` adds a Uvicorn-based Python app - - `AddUv` adds a Uv environment setup task: `uv sync` - - `AddViteApp` registers your React frontend - - `WithReference` connects the frontend to the API—it injects the API's URL and sets up service discovery - - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors - - `PublishWithContainerFiles` bundles the frontend for production deployment - - - - ```typescript title="TypeScript — apphost.ts" - import { createBuilder } from './.modules/aspire.js'; - - const builder = await createBuilder(); - - // Run the Express API and expose its HTTP endpoint externally. - const app = await builder - .addNodeApp("app", "./api", "src/index.ts") - .withHttpEndpoint({ env: "PORT" }) - .withExternalHttpEndpoints(); - - // Run the Vite frontend after the API and inject the API URL for local proxying. - const frontend = await builder - .addViteApp("frontend", "./frontend") - .withReference(app) - .waitFor(app); - - // Bundle the frontend build output into the API container for publish/deploy. - await app.publishWithContainerFiles(frontend, "./static"); - - await builder.build().run(); - ``` - - _What's happening here?_ - - - `createBuilder` creates the distributed application builder - - `addNodeApp` adds a Node.js application (the Express API) - - `addViteApp` registers your React frontend - - `withReference` connects the frontend to the API—it injects the API's URL and sets up service discovery - - `waitFor` ensures the API is running before starting the frontend, preventing connection errors - - `publishWithContainerFiles` bundles the frontend for production deployment - - - This template uses a TypeScript AppHost. To learn more about how multi-language AppHosts work, see [Multi-language architecture](/architecture/multi-language-architecture/). - - - - - - - - -## Run the app - -import csharpDashboardLight from '@assets/get-started/csharp-aspire-dashboard-light.png'; -import csharpDashboardDark from '@assets/get-started/csharp-aspire-dashboard-dark.png'; -import pythonDashboardLight from '@assets/get-started/python-aspire-dashboard-light.png'; -import pythonDashboardDark from '@assets/get-started/python-aspire-dashboard-dark.png'; -import javascriptDashboardLight from '@assets/get-started/javascript-aspire-dashboard-light.png'; -import javascriptDashboardDark from '@assets/get-started/javascript-aspire-dashboard-dark.png'; - - - -1. Change to the _output_ directory: - - - - ```bash title="Change directories" - cd ./AspireApp - ``` - - - - - ```bash title="Change directories" - cd ./aspire-app - ``` - - - -1. Call `aspire run` to start dev-time orchestration: - - ```bash title="Run dev-time orchestration" - aspire run - ``` - - When you run this command, the Aspire CLI: - - - Automatically finds the AppHost - - Builds your solution - - Launches dev-time orchestration - - Once the dashboard is ready, its URL (with a login token—highlighted in the example output below) appears in your terminal. The dashboard provides a live, real-time view of your running resources and their current states. - - - - ```bash title="Example output" mark={8} - 🔍 Finding apphosts... - AspireApp.AppHost/AspireApp.AppHost.csproj - - 🗄 Created settings file at '.aspire/settings.json'. - - AppHost: AspireApp.AppHost/AspireApp.AppHost.csproj - - Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 - - Logs: %USERPROFILE%/.aspire/cli/logs/apphost-13024-2025-10-31-19-40-58.log - - Press CTRL+C to stop the apphost and exit. - ``` - - - - - ```bash title="Example output" mark={8} - 🔍 Finding apphosts... - apphost.cs - - 🗄 Created settings file at '.aspire/settings.json'. - - AppHost: apphost.cs - - Dashboard: https://localhost:17213/login?t=2b4a2ebc362b7fef9b5ccf73e702647b - - Logs: $HOME/.aspire/cli/logs/apphost-27732-2025-10-31-19-21-27.log - - Press CTRL+C to stop the apphost and exit. - ``` - - - ```bash title="Example output" mark={6} - 🔍 Finding apphosts... - apphost.ts - - AppHost: apphost.ts - - Dashboard: https://localhost:17174/login?t=afb274c630f48b1c4ddfe139011c1cb7 - - Logs: %USERPROFILE%/.aspire/logs/cli_20260318T134627_f31ad598.log - - Press CTRL+C to stop the apphost and exit. - ``` - - - - For further CLI reference, see [`aspire run`](/reference/cli/commands/aspire-run/) command information. - - -1. Explore the running distributed application. From the dashboard, open the `HTTPS` endpoint from each resource. - - - - - - - - - - - - - To learn more, see [Aspire dashboard overview](/dashboard/overview/). - - - - -## Stop the app - - - -1. Stop the AppHost and close the dashboard by pressing in your terminal. - - ```bash title="Stop dev-time orchestration" - 🛑 Stopping Aspire. - ``` + + + + - **🥳 Congratulations! You've created your first Aspire app.** +## Before you begin - +Before following either quickstart, make sure you've completed the [prerequisites](/get-started/prerequisites/) and [installed the Aspire CLI](/get-started/install-cli/). -You might be eager to deploy this app next—and we'll show you how Aspire handles that—but you're probably also wondering: "How do I _test_ all this?" Great question! Aspire doesn't just orchestrate locally and deploy, it also helps you test service and resource integrations too. Ready to dive in? [Write your first test](/testing/write-your-first-test/) 💜 +After completing either quickstart, continue with [Deploy your first Aspire app](/get-started/deploy-first-app/). - -## See also - -- Having trouble? Check out our [Troubleshooting guide](/get-started/troubleshooting/) for solutions to common problems. -- Prefer a GUI? The [Aspire VS Code extension](/get-started/aspire-vscode-extension/) lets you create, run, and debug Aspire apps from VS Code. \ No newline at end of file From 3ec45abf5395c660ed2d8bef5abfcef70cb078d2 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 22 Mar 2026 00:17:49 -0700 Subject: [PATCH 3/4] Refine AppHost language getting started copy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...aspire-existing-app-typescript-apphost.mdx | 66 ++++++++++--------- .../get-started/add-aspire-existing-app.mdx | 8 +-- .../content/docs/get-started/first-app.mdx | 8 +-- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx index 62e41e758..25043c0bd 100644 --- a/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx @@ -30,7 +30,6 @@ Before you begin, ensure you have the following prerequisites installed: ### Common requirements -- [.NET SDK 10.0 or later](/get-started/prerequisites/) — Required for the Aspire AppHost, regardless of your application's language. - [Aspire CLI installed](/get-started/install-cli/) — For orchestration and deployment commands. - An existing application to add Aspire to. @@ -89,17 +88,17 @@ The `aspire init` command is the starting point for adding Aspire to your existi 2. Run `aspire init` to initialize Aspire support: - ```bash title="Initialize Aspire with a TypeScript AppHost" + ```bash title="Initialize Aspire with a TypeScript AppHost" aspire init --language typescript ``` - The `aspire init` command runs in **interactive mode** by default. It will: + The `aspire init` command still runs in **interactive mode** for the remaining setup. It will: @@ -151,6 +150,10 @@ After running `aspire init --language typescript`, your project will have a Type A typical monorepo with Node.js API, React storefront, and admin dashboard. + + @@ -294,13 +297,13 @@ await builder ``` -When you call `WithReference`, you're declaring a dependency between resources. Aspire handles the rest—automatically injecting configuration at runtime and during deployment so your services can communicate seamlessly, whether running locally or in production. +When you call `withReference`, you're declaring a dependency between resources. Aspire handles the rest—automatically injecting configuration at runtime and during deployment so your services can communicate seamlessly, whether running locally or in production. ## Add telemetry configuration (optional) -JavaScript/Node.js applications can also send telemetry using OpenTelemetry: +TypeScript Node.js applications can also send telemetry using OpenTelemetry. The example below uses TypeScript and ESM imports so it fits naturally into a TypeScript codebase. If your app uses plain JavaScript, keep the same structure but use `.js` files and your existing module syntax. @@ -315,29 +318,28 @@ JavaScript/Node.js applications can also send telemetry using OpenTelemetry: 2. Create a telemetry configuration file: - ```javascript title="JavaScript — telemetry.js" - const { NodeSDK } = require('@opentelemetry/sdk-node'); - const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); - const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); - const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc'); - const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics'); - const { resourceFromAttributes } = require('@opentelemetry/resources'); - const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions'); + ```typescript title="TypeScript — telemetry.ts" + import { NodeSDK } from '@opentelemetry/sdk-node'; + import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; + import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; + import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; + import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; + import { resourceFromAttributes } from '@opentelemetry/resources'; + import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; - const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317'; + const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? 'http://localhost:4317'; - // Create resource with service name const resource = resourceFromAttributes({ - [ATTR_SERVICE_NAME]: 'frontend', + [ATTR_SERVICE_NAME]: 'api', }); const sdk = new NodeSDK({ - resource: resource, - traceExporter: new OTLPTraceExporter({ url: otlpEndpoint }), - metricReader: new PeriodicExportingMetricReader({ - exporter: new OTLPMetricExporter({ url: otlpEndpoint }) - }), - instrumentations: [getNodeAutoInstrumentations()] + resource, + traceExporter: new OTLPTraceExporter({ url: otlpEndpoint }), + metricReader: new PeriodicExportingMetricReader({ + exporter: new OTLPMetricExporter({ url: otlpEndpoint }), + }), + instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); @@ -345,11 +347,13 @@ JavaScript/Node.js applications can also send telemetry using OpenTelemetry: 3. Import the telemetry configuration at the top of your application entry point: - ```javascript title="JavaScript — app.js" + ```typescript title="TypeScript — src/server.ts" // This must be first! - require('./telemetry'); + import './telemetry'; + + import express from 'express'; - const express = require('express'); + const app = express(); // ... rest of your app ``` @@ -487,9 +491,9 @@ Now that you've added Aspire to your application, it's time to run it and see th The [Aspire dashboard](/dashboard/explore/) provides valuable insights even if you haven't added integrations or telemetry yet. You'll see basic information about your services, their startup order, and their endpoints. -### Bonus content +### Compare with Docker Compose -If you're currently using Docker Compose to orchestrate your services, Aspire can replace it while providing additional benefits: +If you're currently using Docker Compose, the example below shows how the same relationships translate into a TypeScript AppHost: @@ -553,16 +557,14 @@ The orchestration pattern stays the same: model the shared dependencies once, th **Key advantages of Aspire over Docker Compose:** -- **Literally, less verbose** — Yet, more expressive and powerful. - **No manual URL configuration** — Services discover each other automatically. - **Code-based resource references** — Define service dependencies in code instead of duplicating them in YAML. - **Built-in dashboard** — Observability without additional tools like Prometheus/Grafana. -- **Development and deployment** — Same orchestration code works locally and can generate Docker Compose or deploy anywhere. +- **Reusable orchestration code** — The same AppHost definitions work locally and can also drive deployment targets. - **Integration libraries** — Pre-built support for databases, caches, message queues with best practices. -- **JavaScript-friendly** — Works well with JavaScript and TypeScript apps plus containerized services. ## Next steps diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx index 82974be01..2e3eee77e 100644 --- a/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app.mdx @@ -8,21 +8,21 @@ next: false import { Aside, CardGrid, LinkCard } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; -When you add Aspire to an existing application, the first choice is the language of the AppHost. Your services can stay in their current languages while the AppHost handles orchestration, service discovery, configuration injection, and local startup. +When you add Aspire to an existing application, the first choice is the language of the AppHost. Choosing a C# or TypeScript AppHost lets you stay in a familiar toolchain while still using the AppHost to orchestrate services, define resources, and model relationships for the application you already have. diff --git a/src/frontend/src/content/docs/get-started/first-app.mdx b/src/frontend/src/content/docs/get-started/first-app.mdx index 62a748ca2..76f2c7df3 100644 --- a/src/frontend/src/content/docs/get-started/first-app.mdx +++ b/src/frontend/src/content/docs/get-started/first-app.mdx @@ -8,21 +8,21 @@ next: false import { Aside, CardGrid, LinkCard } from '@astrojs/starlight/components'; import LearnMore from '@components/LearnMore.astro'; -Build your first Aspire app by first choosing the AppHost language you want to work in. The AppHost is the code-first orchestrator for your solution, so this choice determines whether your walkthrough uses `AppHost.cs` / `apphost.cs` or `apphost.ts`. +Build your first Aspire app by first choosing the AppHost language you want to work in. The AppHost is the code-first orchestrator for your solution, so this choice lets you stay in a familiar toolchain while deciding whether your walkthrough uses `AppHost.cs` / `apphost.cs` or `apphost.ts`. From ddce4e463471e86393514e9059c2ab458c89a18a Mon Sep 17 00:00:00 2001 From: David Pine Date: Sun, 22 Mar 2026 12:35:25 -0500 Subject: [PATCH 4/4] Refactor documentation for clarity and consistency across AppHost guides --- src/frontend/config/sidebar/docs.topics.ts | 44 +++++++++---------- ...aspire-existing-app-typescript-apphost.mdx | 2 +- .../get-started/first-app-csharp-apphost.mdx | 10 ++--- .../first-app-typescript-apphost.mdx | 35 +++------------ 4 files changed, 32 insertions(+), 59 deletions(-) diff --git a/src/frontend/config/sidebar/docs.topics.ts b/src/frontend/config/sidebar/docs.topics.ts index bbc9f5ab6..02a7c6d10 100644 --- a/src/frontend/config/sidebar/docs.topics.ts +++ b/src/frontend/config/sidebar/docs.topics.ts @@ -290,32 +290,32 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { uk: 'Створіть свій перший додаток', 'zh-CN': '构建您的第一个应用', }, - badge: { - text: 'Quickstart', - variant: 'tip', - translations: { - da: 'Hurtigstart', - de: 'Schnellstart', - en: 'Quickstart', - es: 'Inicio rápido', - fr: 'Démarrage rapide', - hi: 'त्वरित आरंभ', - id: 'Memulai Cepat', - it: 'Avvio rapido', - ja: 'クイックスタート', - ko: '빠른 시작', - 'pt-BR': 'Início Rápido', - 'pt-PT': 'Início Rápido', - ru: 'Быстрый старт', - tr: 'Hızlı Başlangıç', - uk: 'Швидкий старт', - 'zh-CN': '快速开始', - }, - }, items: [ { label: 'Overview', slug: 'get-started/first-app', + badge: { + text: 'Quickstart', + variant: 'tip', + translations: { + da: 'Hurtigstart', + de: 'Schnellstart', + en: 'Quickstart', + es: 'Inicio rápido', + fr: 'Démarrage rapide', + hi: 'त्वरित आरंभ', + id: 'Memulai Cepat', + it: 'Avvio rapido', + ja: 'クイックスタート', + ko: '빠른 시작', + 'pt-BR': 'Início Rápido', + 'pt-PT': 'Início Rápido', + ru: 'Быстрый старт', + tr: 'Hızlı Başlangıç', + uk: 'Швидкий старт', + 'zh-CN': '快速开始', + }, + }, }, { label: 'C# AppHost', diff --git a/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx index 25043c0bd..4842133ed 100644 --- a/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx +++ b/src/frontend/src/content/docs/get-started/add-aspire-existing-app-typescript-apphost.mdx @@ -458,7 +458,7 @@ Now that you've added Aspire to your application, it's time to run it and see th 2. The dashboard URL will appear in your terminal output: - ```bash title="Example output" mark={4} + ```bash title="Example output" mark={3} 🔍 Finding apphosts... Dashboard: https://localhost:17068/login?t=ea559845d54cea66b837dc0ff33c3bd3 diff --git a/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx b/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx index 4c79d453c..5316639c0 100644 --- a/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx +++ b/src/frontend/src/content/docs/get-started/first-app-csharp-apphost.mdx @@ -23,6 +23,7 @@ This quickstart uses starter templates that generate a C# AppHost. Choose the ap and keys to navigate the options. Press to confirm your selection. - - ## Review the template code @@ -242,8 +241,7 @@ To create your first Aspire application, use the [Aspire CLI](/get-started/insta - `WaitFor` ensures the API is healthy before starting the frontend, preventing connection errors - `PublishWithContainerFiles` bundles the frontend for production deployment - - +