콘텐츠로 이동

Aspireify an existing app

이 콘텐츠는 아직 번역되지 않았습니다.

Select your application's primary language

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.

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), 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.

Before you begin, ensure you have the following prerequisites installed based on your application’s language:

  • .NET SDK 10.0 or later — Required for the Aspire AppHost, regardless of your application’s language.
  • Aspire CLI installed — For orchestration and deployment commands.
  • An existing application to add Aspire to.

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 installed
  • 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 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

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

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:

    Navigate to your solution directory
    cd /path/to/your-solution
    Navigate to your project root
    cd /path/to/your-project
    Navigate to your workspace root
    cd /path/to/your-workspace
  2. Run aspire init to initialize Aspire support:

    Initialize Aspire
    aspire init

    The aspire init command runs in interactive mode by default. It will:

    • Detect your existing solution structure
    • Create a file-based AppHost (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.

After running aspire init, your project will have a file-based AppHost:

  • ExampleEcommerce.sln
  • apphost.cs (new) orchestration code
  • apphost.run.json (new) configuration
  • 디렉터리src/
    • 디렉터리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.

  • 디렉터리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.

  • 디렉터리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 initially contains a minimal starter:

apphost.cs — Initial state after aspire init
#:sdk Aspire.AppHost.Sdk@13.0.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.

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.

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<T> (or AddCSharpApp for file-based apps).

For Python applications, install the Python hosting package:

Aspire CLI — Aspire.Hosting.Python 패키지 추가
aspire add python

Aspire CLI는 대화형입니다. 프롬프트 시 알맞은 검색 결과 선택:

Aspire CLI — 출력 예시
Select an integration to add:
> python (Aspire.Hosting.Python)
> Other results listed as selectable options...

This package provides methods like AddUvicornApp, AddPythonApp, and AddPythonModule.

For JavaScript/TypeScript applications, install the JavaScript hosting package:

Aspire CLI — Aspire.Hosting.JavaScript 패키지 추가
aspire add javascript

Aspire CLI는 대화형입니다. 프롬프트 시 알맞은 검색 결과 선택:

Aspire CLI — 출력 예시
Select an integration to add:
> javascript (Aspire.Hosting.JavaScript)
> Other results listed as selectable options...

This package provides methods like AddViteApp, AddNodeApp, and AddJavaScriptApp.

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:

apphost.cs — Complete e-commerce example
#:sdk Aspire.AppHost.Sdk@13.0.0
var builder = DistributedApplication.CreateBuilder(args);
var api = builder.AddProject<Projects.ExampleEcommerce_Api>("api")
.WithHttpHealthCheck("/health");
var web = builder.AddProject<Projects.ExampleEcommerce_Web>("web")
.WithExternalHttpEndpoints()
.WithReference(api)
.WaitFor(api);
var orderProcessor = builder.AddProject<Projects.ExampleEcommerce_OrderProcessor>("orderprocessor")
.WithReference(api);
builder.Build().Run();

Key methods:

  • AddProject<T> - 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:

apphost.cs — Complete SaaS example
#:sdk Aspire.AppHost.Sdk@13.0.0
#:package Aspire.Hosting.Python@13.0.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:

apphost.cs — Complete monorepo example
#:sdk Aspire.AppHost.Sdk@13.0.0
#:package Aspire.Hosting.JavaScript@13.0.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

The calls to WithReference establish service dependencies and enable service discovery:

apphost.cs — Connect .NET services
// Omitted for brevity...
var api = builder.AddProject<Projects.YourApi>("api");
var web = builder.AddProject<Projects.YourWeb>("web")
.WithReference(api); // Web can call API
var worker = builder.AddProject<Projects.YourWorker>("worker")
.WithReference(api); // Worker can call API
// Omitted for brevity...
apphost.cs — Connect Python services
// 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...
apphost.cs — Connect JavaScript services
// 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.

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:

    .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:

    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.

Python applications can send telemetry to the Aspire dashboard using OpenTelemetry:

  1. Install OpenTelemetry packages in your Python application:

    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 — 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:

    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 — 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 { Resource } = require('@opentelemetry/resources');
    const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317';
    const sdk = new NodeSDK({
    resource: new Resource({ 'service.name': 'frontend' }),
    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 — app.js
    // This must be first!
    require('./telemetry');
    const express = require('express');
    // ... rest of your app

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:

    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:

    apphost.cs — Add Redis integration for polyglot apps
    var builder = DistributedApplication.CreateBuilder(args);
    // Add Redis resource
    var cache = builder.AddRedis("cache");
    // Share Redis with .NET API
    var api = builder.AddProject<Projects.YourApi>("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:

    Add Redis client to .NET project
    dotnet add YourApi package Aspire.StackExchange.Redis
    Program.cs — Configure Redis client
    var builder = WebApplication.CreateBuilder(args);
    builder.AddRedisClient("cache");
    Add Redis client to Python project
    uv add redis
    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
    )
    Add Redis client to Node.js project
    npm install redis
    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.

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:

    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:

    Example output
    🔍 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 ⌘+C Control + C Control + C in your terminal.

If you’re currently using Docker Compose to orchestrate your services, Aspire can replace it while providing additional benefits:

docker-compose.yml
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

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.

Congratulations! You’ve successfully added Aspire to your existing application. Here are some recommended next steps:

질문 & 답변협업커뮤니티토론보기