Polyglot Aspire

One app model.
Any AppHost.
Any workload.

Chris Ayers

Principal Software Engineer · Microsoft

Chris Ayers

Principal Software Engineer
Azure EngOps AzRel
Microsoft

BlueSky: @chris-ayers.com
LinkedIn: - chris-l-ayers
Blog: https://chris-ayers.com/
GitHub: Codebytes
Mastodon: @Chrisayers@hachyderm.io

The problem

The Polyglot Problem

Modern apps are an orchestra with no conductor, and for polyglot teams,
every section is reading from a different score.

Your team doesn't use one language. It uses five.

Your stack today

  • Python ML services
  • Go microservices
  • Java Spring Boot APIs
  • TypeScript/React frontends
  • .NET backend APIs

The question: How do you orchestrate, observe, and wire all of this from one place?

The problem

The Orchestration Pain

Five stacks. Five toolchains. Zero shared model.

  • 🚢 Docker Compose: explicit endpoint, dependency, and health-check configuration; telemetry is separate
  • 📄 Config sprawl: .env, YAML, application.properties, appsettings.json, each with its own format
  • 🔍 No unified observability: good luck tracing a request across four services in three runtimes
  • 📜 15-step READMEs: "just docker-compose up" never works first time

Aspire: The Polyglot Answer

Aspire is an agent-ready, code-first tool to compose, debug, and deploy any distributed app.

The answer

What Collapses Into One

An illustrative five-service team—not a measured benchmark:

Startup commands
5
1
Connection-wiring sources
4
1
Observability panes
3
1
Without AspireWith Aspire
The answer

The Four Pillars

Polyglot Aspire
🛠
Aspire CLI
Control plane
One command set to start, inspect, and deploy the stack.
🗺
Aspire AppHost
Stack in code
Services, dependencies, and endpoints declared together in code.
📊
Aspire Dashboard
App at a glance
Resource state, logs, traces, metrics, and interactive terminals.
🧩
Aspire Integrations
Building blocks
100+ packages for data, messaging, AI, and clouds.
The answer

One Orchestrator. Every Language.

Workload runtimes

🐍 Python · 🐹 Go · ☕ Java

🟦 TypeScript · 💜 .NET · 🦀 Rust

Aspire AppHost

C# · TypeScript

Python · Go · Java · Rust (preview)

one run · one model

Same capabilities

🎯 Orchestration

🔗 Service discovery

📊 OpenTelemetry

The answer

The Dashboard: One View for Everything

Aspire 13.6 dashboard showing structured logs with the run selector open on an earlier run
Source: Microsoft Aspire 13.6 announcement

Follow one request: browser → API → backing service.

Resource state, endpoints, logs, and traces share one view.

The answer

Demo: Vite React + FastAPI

TypeScript AppHostReactFastAPIRedis

center

Live: Add a TODO → reload → follow its browser-to-API trace.

How It Works

From AppHost code to running resources and connected services

How it works

The AppHost: C#

Write your AppHost in the language your team knows. Here's C#:

var builder = DistributedApplication
    .CreateBuilder(args);

var redis = builder.AddRedis("cache");

builder.AddPythonApp("api", "../api", "app.py")
       .WithReference(redis)
       .WithHttpEndpoint(env: "PORT");

builder.Build().Run();

Declare resources and their relationships together.

How it works

The AppHost: TypeScript

Same app model. A different authoring language.

import { createBuilder } from "./.aspire/modules/aspire.mjs";

const builder = await createBuilder();

const cache = await builder.addRedis("cache");
const api = await builder.addPythonApp("api", "../api", "app.py")
  .withReference(cache);

await builder.addViteApp("web", "../web").withReference(api);
await builder.build().run();

Generated SDK. Familiar resources, references, and endpoints.

How it works

ATS: One Model, Multiple Languages

The Aspire Type System exposes hosting APIs to guest AppHost languages.

Guest AppHost

TypeScript

Python · Go · Java · Rust (preview)

ATS

Typed SDK
local JSON-RPC

.NET Hosting APIs

Resources
integrations

Generated SDKs live in .aspire/modules/.

How it works

DCP: Turn the Model into Processes

The Developer Control Plane runs the local resource graph.

AppHost Model

Resources
dependencies

DCP

Start · connect
monitor · stop

Running App

Containers
processes

Development-time only. Production uses the selected deployment target.

How it works

Architecture Overview

The model becomes running resources and a shared telemetry view.

center

How it works

Start with a Workload Integration

Keep the workload's toolchain. Let Aspire model how it runs.

  • 🐍 Python / ASGI → AddPythonApp() · AddUvicornApp()
  • 🟦 JavaScript / TypeScript → AddJavaScriptApp() · AddNodeApp()
  • ⚡ Vite frontend → AddViteApp()
  • 💜 .NET project → AddProject<T>()
  • 🐹 Go / Bun → AddGoApp() · AddBunApp()
  • ☕ Java · 🦀 Rust → AddSpringBootApp() · AddRustApp() (preview)

Prefer a typed integration when one fits.

How it works

Bring the Rest of Your Stack

More integrations

  • Deno: AddDenoApp()
  • Blazor WASM: AddBlazorWasmProject()

Deno: experimental (13.6).
Blazor hosting: preview.

Universal options

  • AddDockerfile() — build an image
  • AddContainer() — use an image
  • AddExecutable() — run a process

If it runs, it can join the model.

Infrastructure joins the same graph: Redis · PostgreSQL · Kafka · Cosmos DB.

How it works

Wire Connections and Readiness

.WithReference(redis)           // pass connection info
.WaitFor(redis)                 // wait for readiness
.WithHttpEndpoint(env: "PORT")   // expose HTTP
.WithExternalHttpEndpoints()    // public ingress
.WithHttpHealthCheck("/health") // readiness probe

A reference supplies configuration. A wait supplies startup ordering.

How it works

Resource Lifecycle Management

Resource lifecycle from starting through stopped
Aspire keeps startup order, monitoring, and shutdown coordinated across the whole app.

Startup Gating: WaitFor(...) holds dependents until a resource is ready
Health Monitoring: WithHttpHealthCheck("/health") reports readiness and status
Graceful Shutdown: Clean termination of all processes

How it works

Service Discovery: The Pattern

Aspire injects service endpoints as environment variables:

# Pattern: services__<name>__<protocol>__<index>
services__api__http__0=http://localhost:5000
services__frontend__http__0=http://localhost:3000

Why double underscore? __ represents configuration hierarchy using shell-friendly names.

No hardcoded service addresses. Application configuration and toolchains stay in place.

How it works

Connection Strings: The Pattern

Connection strings use ConnectionStrings__<resource>:

ConnectionStrings__messaging=localhost:9092
ConnectionStrings__recipesdb=<provider connection string>

Typed Redis resources also expose CACHE_URI. Use the complete URI:

import os
import redis

client = redis.Redis.from_url(os.environ["CACHE_URI"])

Case matters in Python/Linux. A connection string is not always a URI.

Practical Setup

Run and inspect. Automate team tasks. Connect agents.

Practical setup

Create Your First App

Install with a familiar package manager: get.aspire.dev

npm install -g @microsoft/aspire-cli
aspire new aspire-ts-starter -n my-app
cd my-app
aspire run

One coherent path: install → scaffold → run.

Practical setup

Work with a Running Stack

Inspect the model and its resources; do not guess ports or processes.

aspire start     # Background
aspire ps        # AppHost summaries
aspire describe  # Resource details
aspire doctor    # Environment
aspire logs      # Console output
aspire stop      # Stop the app

ps summarizes AppHosts. describe shows resources.

Practical setup

Turn README Steps into Resource Commands

Define a workflow once. Use it from the dashboard or CLI.

Quotes Board: one custom seed command, two interfaces.

cd samples/dotnet-react-postgres
aspire resource api seed --help
aspire resource api seed --count 5
Dashboardcollects named inputs
CLIaccepts named options

Stable in 13.5: command arguments and core prompts.

Practical setup

Let a Command Ask for a File

A guided import

  • Choose quotes.json
  • Validate content and size
  • Import the whole batch

Stable: file inputs.
Experimental: progress dialogs.

Quotes Board Import quotes dialog with quotes.json selected and a 128 KiB file limit
Live Quotes Board sample · Aspire dashboard
Practical setup

Demo: Quotes Board Commands

C# AppHostReactPostgreSQL

Seed from the terminal. Import from the dashboard.

aspire resource api seed --count 5
Seed quotesone named count argument
Import quoteschoose demo/quotes.json

Click Refresh quotes → see new entries and the updated count.

Same application. Two repeatable workflows.

Practical setup

Not Everything Is an HTTP Service

Experimental since 13.5: REPLs, shells, and TUIs are resources too.

Interactive JavaScript guessing game accepting input in the Aspire dashboard terminal
Cropped from the Microsoft Aspire 13.5 announcement

Enable .WithTerminal() / .withTerminal() on a resource.

Real input and output. One session, multiple viewers.

cd samples/terminal-demo
aspire terminal ps
aspire terminal attach node-repl
Practical setup

A Database Shell, Already Signed In

New in 13.6 (preview): WithRepl() adds a REPL command to data resources.

Aspire dashboard with a running Redis cache resource and a docked redis-cli tab showing PING and PONG
Source: aspire.dev: Use interactive terminals in the dashboard

The container's own client opens in the dashboard's terminal dock.

PostgreSQL · MySQL · SQL Server · MongoDB · Redis · Valkey

builder.AddPostgres("postgres")
       .WithRepl();
Practical setup

Agent-Ready CLI

Skills for workflow. MCP for runtime context.

Start with Aspire skills. Add MCP when the agent needs live application data.

🧭 Aspire skills

Teach agents the CLI, AppHost conventions, and debugging workflows.

Install project guidance with aspire agent init.

🔌 Aspire MCP

The agent starts aspire agent mcp as a local stdio subprocess.

Read resource state, logs, and traces; execute resource commands.

One runtime view across Python, Go, Java, Rust, Node.js, and .NET.

Practical setup

Wire It Up in 30 Seconds

Install skills first; select the MCP server when you need runtime access.

In your AppHost directory

aspire agent init
# Select skills; optionally MCP
aspire run

Open your configured coding agent; it launches MCP on demand.

Generated VS Code config

{ "servers": {
    "aspire": {
      "type": "stdio",
      "command": "aspire",
      "args": ["agent", "mcp"]
    }
} }

More Polyglot Demos

From HTTP requests to event-driven workflows: 16 verified samples

More demos

Five Languages, One Dashboard

Across 16 samples: an authored AppHost or workload in each language

JavaScript / TS
9
C# / .NET
8
Python
6
Go
3
Java
2
5 languages · 16 samples · 1 dashboard experience
More demos

Demo: Polyglot Event Stream

C# AppHost.NETPythonNode.jsKafka
Polyglot event stream with Kafka The .NET producer publishes a sensor reading to the Kafka sensor-readings topic every 2 seconds, and Kafka delivers each reading to both the Python consumer and the Node.js dashboard. A custom reading of 42.5 °C and 95% humidity exceeds the alert thresholds, so the Python consumer publishes an alert to sensor-alerts, which the dashboard also consumes. The browser polls the dashboard over HTTP every 5 seconds. .NET ProducerHTTP API • dynamic port Apache Kafkaevent bus • Port 9092 Node.js DashboardHTTP + JSON • dynamic port Python Consumerrolling averages + alerts Browser sensor-readings both topics sensor-readings ↓ sensor-alerts ↑ HTTP polling every 5 s POST /api/events 42.5 °C · 95% humidity ! Anomaly detected temp > 35 °C · humidity > 90% ! Alert reaches dashboard
sensor reading · every 2 salert · sensor-alertsbrowser poll · every 5 s
Deploy

Same Model. Explicit Deployment Target.

Add a target integration and resource to the AppHost:

#:package Aspire.Hosting.Docker@13.6.1
// Alongside the API, cache, and their references:
builder.AddDockerComposeEnvironment("compose");
aspire runlocal development
aspire deployconfigured target

Reuse the app model; select where it runs.

Deploy

Production Choices Stay Explicit

Where will it run?

  • Deployment platform
  • Image registry and credentials

What does it need?

  • Persistent storage
  • Ingress, certificates, and access

13.5 preview: Kubernetes persistent-volume APIs (ASPIRECOMPUTE002).

aspire publish emits artifacts; aspire do runs named pipeline steps.

Deploy

A Verified Publish Path: Go + Redis

The same model was tested locally and as a published Compose stack.

# From samples/go-redis-compose
aspire publish -o compose-output
docker build -t hitcounter-api:local src/api
cd compose-output
API_IMAGE=hitcounter-api:local docker compose up -d
docker compose port api 8080

Open /api/hits on the reported host port. Refresh → the Redis counter increases.

Verified: generated artifacts, working API, and counter retention across API restart.

Deploy

Demo: AppHost to Azure Bicep

C# AppHostAngular + .NETContainer AppsCosmos DB
cd samples/dotnet-angular-cosmos
aspire publish --apphost AppHost/AppHost.csproj \
  -o aspire-output/bicep --non-interactive
Inspectinfrastructure + app modules
Compile8 Bicep templates → ARM JSON

Publish is not deploy. No Azure resources are created.

Wrap-Up

Wrap-up

Observability Without Rewrites

Already emitting OpenTelemetry? Add a standalone dashboard.

docker run --rm -d --name aspire-demo-dashboard \
  -p 127.0.0.1:18888:18888 \
  -p 127.0.0.1:4317:18889 -p 127.0.0.1:4318:18890 \
  mcr.microsoft.com/dotnet/aspire-dashboard:latest

docker logs aspire-demo-dashboard

Open the login URL from the logs. UI: 18888 · OTLP/gRPC: 4317 · OTLP/HTTP: 4318

No .NET app required. Adopt the AppHost when you also need service wiring and lifecycle.

Wrap-up

Key Takeaways

  • 🎯 Two independent choices, one model: Pick the AppHost language and workload runtimes separately
  • 📊 One observability view: Connect instrumented workloads through OpenTelemetry
  • 🚀 Reuse the model; choose the target: Production configuration stays explicit

Start with one service. Follow one request. Automate one team task.

Wrap-up

Resources

Questions?

We've all been there. The README says "just run docker-compose up" but it never works the first time. Five languages, one app, no map.

Each pain point appears on its own click. Compose supports health-aware startup with healthcheck and depends_on.condition: service_healthy. The contrast is the configuration you maintain and the separate telemetry tooling, not a missing Compose capability. Source: https://docs.docker.com/compose/how-tos/startup-order/

Use the official positioning sentence verbatim. Promise a concrete outcome: run a mixed-language app, follow one request, and understand the model that wires it together. The next slides preview that workflow and its four building blocks.

This is an illustrative before/after workflow, not repository benchmark data. One aspire run can coordinate five startup commands; the AppHost centralizes endpoint wiring previously spread across four places, and the dashboard brings telemetry into one view. Language toolchains and application configuration files still exist. Generated deployment artifacts can still include YAML and .env files.

Four pillars hold up the whole model: the CLI drives it, the AppHost declares it, the Dashboard shows it, and Integrations plug into it. Same four regardless of language.

Polyglot has two independent axes: the language used to author the AppHost and the languages used by its workloads. Six languages funnel into one orchestrator, and out come the same three capabilities: orchestration, service discovery, and observability. In 13.6, Java and Rust hosting became first-party (preview), and Rust joined Python, Go, and Java as a preview AppHost language behind an experimental feature flag.

Core: show resources, their endpoints, and one request's trace. Console logs capture stdout/stderr; structured logs, traces, and metrics require OpenTelemetry SDK/exporter setup. Aspire supplies OTEL_EXPORTER_OTLP_ENDPOINT; it does not instrument every workload automatically. Transition: prove the polyglot promise with a TypeScript AppHost running React, FastAPI, and Redis. Save the release details below for questions rather than delaying the first demo. Optional 13.6 callout: the dashboard keeps resource snapshots and telemetry after the AppHost stops. Each start begins a new run, and the run selector switches between live and read-only past runs. Filtering, search, paging, and aggregation work on past runs. It keeps up to 10 runs per application and prunes the oldest; pin a run to keep it. Runs are SQLite databases on disk, so a coding agent can compare them. Default limits rose to 100,000 entries each for console logs, structured logs, and traces. Persisted telemetry can contain sensitive values, and the on-disk database has no separate encryption or authorization layer. The dashboard remains a development and short-term diagnostics tool, not a production telemetry backend. Run history requires Aspire 13.6. This repository's samples run on 13.6.1, so restart any sample to show the run selector live. Optional: demonstrate a case-insensitive console-log search, then narrow logs or traces by timestamp and exact numeric comparisons (added in 13.5). Screenshot is the official release-post example, not a capture of this repository's demos. Sources: https://devblogs.microsoft.com/aspire/whats-new-aspire-13-6/ and https://aspire.dev/dashboard/data-persistence/ Image: https://devblogs.microsoft.com/aspire/wp-content/uploads/sites/90/2026/09/dashboard-run-history.webp (cropped to the run selector and logs).

Question: can a TypeScript AppHost run a Python API and a React frontend without changing their languages or toolchains? From samples/vite-react-api, start aspire run --apphost apphost.mts and open web from aspire describe. For a background worktree run, use aspire start --apphost apphost.mts --isolated. Create a TODO with the Add button, create another with Enter, reload to show Redis-backed storage, then delete the test TODO. Inspect the trace that links a browser client span to the FastAPI server span. Payoff: the AppHost language and workload languages are independent; one model wires the stack and one dashboard exposes the request. Keep this stack running while explaining the model and basic CLI operations. Stop it before the Quotes Board demo. Optional troubleshooting detail: the current/legacy container-hostname mapping in vite.config.ts gives the browser a reachable HTTP collector, not a container-only name or the gRPC port. Transition: now explain what produced that running graph, starting with AppHost code rather than environment-variable conventions.

The mixed-language demo showed the result. Explain cause before effect: author the model, add resources, wire relationships, then inspect the configuration received by each workload.

This is the canonical code example, not another architecture tour. Point out the cache, Python workload, and reference. C# is the original AppHost language. Advance directly to TypeScript: the title and code stay anchored while the authoring language changes.

TypeScript AppHosts became GA in 13.4, when ASPIREATS001 was retired. Aspire 13.5 closes more parity gaps with C#. This does not make every experimental AppHost authoring language GA: keep Python, Go, Java, and Rust preview labels separate from workload support. Custom checks use builder.addHealthCheck(name, check) and resource.withHealthCheck(key). withContainerFiles and withContainerFilesCallback copy or generate container files. Keep these as examples of parity, not another API walkthrough. Current entry points use apphost.mts. aspire update --migrate can migrate older apphost.ts projects. Transition: the generated import raises one question: how does a TypeScript AppHost call the hosting APIs? Answer it with the next paired ATS/DCP slides, then return to choosing and wiring resources. Sources: https://aspire.dev/whats-new/aspire-13-4/ and https://aspire.dev/whats-new/aspire-13-5/

The previous slide imported a generated SDK. This slide answers one question: how can a non-C# AppHost use the hosting APIs? Keep this explanation brief; it supports the model rather than opening a separate internals chapter. C# uses those APIs directly. Guest AppHosts use generated SDKs and a local JSON-RPC transport. Available API surfaces vary by integration and AppHost language; do not imply every package has complete cross-language parity. Pause before the next question: who actually starts the resources? Advance: the model panel slides left to become DCP's input, because DCP runs the model that the hosting APIs build.

DCP is the Go-based, Kubernetes-compatible development orchestrator. The AppHost lowers its model to resource specifications; DCP reconciles those specifications, starts containers/processes, allocates ports, and reports lifecycle state. This is separate from ATS and from the production target. Remember this boundary for the deployment section: reuse the app model, not the local development runtime. Transition: put those pieces back into the architecture we just ran, then show how to add and wire resources.

Connect the architecture to the opening FastAPI demo: the AppHost defines the graph, DCP runs its containers and processes, and instrumented workloads send telemetry to the dashboard. ATS lets guest AppHosts build that model. Now move from the whole picture to the resource choices a team makes.

Each workload appears on its own click. This is a choice map, not a list to memorize. Start with the workload the team already has and select its typed integration. Go (Aspire.Hosting.Go) and Bun (Aspire.Hosting.JavaScript) graduated into core in 13.4. In 13.6, Java and Rust hosting moved from the Community Toolkit into first-party preview packages. Aspire.Hosting.Java adds AddSpringBootApp, AddQuarkusApp, and AddJavaApp (Maven or Gradle wrapper builds, or a prebuilt JAR); Aspire.Hosting.Rust adds AddRustApp for Cargo apps. Both get VS Code debugging and a generated Dockerfile at publish time. Java apps receive the OpenTelemetry exporter settings; add WithOtelAgent() for the Java agent's automatic instrumentation. Pause here: these are helpers for running familiar tools, not replacement language runtimes. Next, show how community integrations and the general-purpose resource types cover the rest of a real stack.

Five clicks: the two integrations, then the three universal options. 13.6 moved Spring Boot into first-party Java hosting, so it now lives on the workload slide. Deno also gained a first-party, experimental AddDenoApp in Aspire.Hosting.JavaScript (ASPIREDENO001), with task and serve modes; it differs from the Community Toolkit's Deno integration and its AddDenoTask. Keep this separate from the first-party workload slide so the audience can see the escape hatches without losing the primary recommendation. The backing-service APIs include AddRedis, AddPostgres(...).AddDatabase(...), AddKafka, and AddAzureCosmosDB. Our recipe demo uses RunAsEmulator, which selects the Linux-based vNext emulator in 13.6, for its local Cosmos DB instance. Hosting packages and preview status vary by integration. The repository demonstrates both typed integrations and raw Dockerfile/container/executable resources. A raw container still needs explicit connection configuration and any health checks the application requires.

The resources are in the model; now describe their relationships. A reference passes configuration, a wait gates startup, and a health check defines readiness. The next slide shows those decisions over the resource's lifecycle. Other useful helpers include WithUv and WithNpm for package managers. WithMcpServer describes a resource's own MCP endpoint; it is separate from the Aspire CLI's runtime MCP server discussed later.

WithReference wires configuration; it does not itself impose startup ordering. Use WaitFor to gate a dependent resource on its dependency's readiness. With a registered health check, WaitFor waits for healthy; without one, it waits for the Running state. WithHttpHealthCheck reports readiness and dashboard status. It does not by itself promise automatic restarts on failure. Production liveness probes and restart policies belong to the deployment orchestrator. Transition: we have declared the resources and their relationships. Next inspect the endpoint and connection settings that workloads receive. Source: https://aspire.dev/fundamentals/health-checks/

Environment names are a portable interface across language runtimes. Double underscores represent the hierarchy in shell-friendly names; do not imply that framework configuration or deployment .env files disappear.

Service discovery and connection strings share one universal interface: environment variables. Use the exact ConnectionStrings__ casing; Linux environment lookups are case-sensitive. AddRedis("cache") plus WithReference exposes CACHE_URI and individual connection properties. CACHE_URI preserves the scheme, host, port, and credentials. Prefixing a StackExchange-style connection string with redis:// does not convert it to a valid URI. A preconfigured AddConnectionString resource exposes the connection string rather than the typed Redis properties. Close the model-to-runtime loop: AppHost code produces configuration that a workload reads using its normal tools. Next move from how the app is wired to how a developer operates it. Source: https://aspire.dev/integrations/caching/redis/redis-connect/

Build from basic operation to advanced workflows: scaffold and run, inspect a running stack, replace README steps with resource commands, then extend those workflows with terminals and agents.

npm is convenient for Node/TypeScript teams; Homebrew, WinGet, mise, Nix, NuGet, and the install script are also supported. Package-manager distribution started in the 13.4 timeframe; do not present every installation option as new in 13.5. Keep the workload's own toolchain installed. For C# use aspire-starter; aspire-py-starter is an experimental Python AppHost path. Show just one scaffold command rather than three competing project creations. This is the audience's on-ramp, not a required live project creation. Keep the opening FastAPI demo running and use it to explain the operating commands next. The starter remains the suggested first experiment after the talk, rather than a second frontend/API demo. Source: https://aspire.dev/get-started/install-cli/

In 13.5, aspire ps summarizes AppHosts; use aspire describe for resource-level details. The old aspire ps --resources and --include-hidden options were removed. Before the talk, run aspire doctor. In VS Code the dashboard no longer auto-opens by default: open it explicitly, or opt in with Aspire: Dashboard Browser / dashboardBrowser in launch.json. Use ordinary aspire stop during the demo. aspire stop --force permanently deletes persistent resource data without an extra confirmation; it is not a harmless "stop harder" option. In a worktree, prefer aspire start --isolated. When several AppHosts exist, specify --apphost rather than stopping or inspecting a different stack. Use the existing FastAPI stack for the basic inspect/log workflow. Transition: inspecting is useful, but the next example turns a team's manual README steps into repeatable resource actions. Source: https://aspire.dev/whats-new/aspire-13-5/

Connect this to the 15-step README problem: an integration author can make import, seed, or reset actions part of the resource model. This is implemented in samples/dotnet-react-postgres/apphost.cs, not a built-in Aspire command. Start that AppHost first. The command appends 1-100 demo quotes through the API; the default count is 5. A count of 0 fails before any database write. Declare CommandOptions.Arguments and read ExecuteCommandContext.Arguments; TypeScript has the corresponding ATS exports. The dashboard collects inputs while the CLI accepts named options and reports missing required values. If an argument collides with an Aspire option, separate command options with --. Pause on the shared workflow before introducing richer input. Sources: https://aspire.dev/fundamentals/custom-resource-commands/ and https://aspire.dev/reference/cli/commands/aspire-resource/

This is the actual Quotes Board file picker, not an illustrative release screenshot. Import quotes uses PromptInputAsync with InputType.File, a .json filter, and a 128 KiB maximum. The AppHost validates uploaded bytes and calls the API's development-only batch endpoint. The entire batch is validated before a PostgreSQL transaction writes it. File imports are dashboard-only in this sample; seed supports both the CLI and dashboard. Canceling before confirmation adds nothing, and demo/invalid-quotes.json demonstrates whole-batch rejection. File inputs and core prompts are stable. Progress dialogs with optional cancellation remain experimental (ASPIREINTERACTION001); they are a dashboard interaction, not a prerequisite for a CLI command. Source: https://aspire.dev/whats-new/aspire-13-5/ Image: captured from samples/dotnet-react-postgres using Aspire 13.5.3.

Question: can a team replace its manual seed/import instructions with one discoverable workflow? Stop the opening FastAPI demo's AppHost first. From samples/dotnet-react-postgres run aspire start --apphost apphost.cs --isolated, then aspire wait api --apphost apphost.cs --status healthy. Open the dashboard and the web resource in separate tabs. Run aspire resource api seed --count 5. Show the added count and IDs, then Refresh quotes in the board. Alternatively choose api > Actions > Seed quotes to show the same named argument in a dialog. Next choose api > Actions > Import quotes, select demo/quotes.json, and click OK. The JSON result reports added: 3. Refresh the board and point to the three fixture authors. If time permits, import demo/invalid-quotes.json and show the failed operation and unchanged count. Both commands append; this is not a reset or deduplicating import. No bespoke admin UI was needed. The source stays file-based: TreatProjectReferencesAsResources=false shares API validation as a normal assembly reference, while AddProject registers the API by path. Keep this AppHost running through the workflow slides. Before switching to another live stack, stop it with aspire stop --apphost apphost.cs; preserve the data volume. Payoff: the same modeled resource exposes repeatable team actions through both the CLI and dashboard. The next slides extend this running-resource workflow with interactive terminals, not another required application demo.

Core: this is a capability callout, not a required AppHost switch. Keep the normal route focused on the Quotes Board workflow; resources can also expose an interactive session. Optional demo: the screenshot shows Microsoft's JavaScript guessing-game playground. The commands use this repository's terminal-demo instead. Stop the Quotes Board AppHost before switching stacks, start terminal-demo with aspire run, evaluate 6 * 7 and process.stdin.isTTY in node-repl, and attach from another terminal to see the same session. Ctrl+B then D detaches without ending the process. Stop terminal-demo before starting the event-stream demo. WithTerminal() and the terminal hosting APIs are experimental (introduced in 13.5). C# callers must suppress ASPIRETERMINAL001. Aspire CLI 13.5 also required features.terminalCommandsEnabled for the terminal commands; 13.6 removes that requirement, so terminal-demo no longer sets it. The AppHost still needs the terminals.v1 capability (Aspire.Hosting 13.4 or later). The dashboard terminal never required the CLI flag. 13.6 also adds aspire terminal tape play for scripting repeatable terminal interactions. Terminal-enabled resources run as plain processes and do not get automatic debugger attachment. Attach the debugger manually from your IDE when needed. Sources: https://aspire.dev/app-host/with-terminal/ and https://aspire.dev/reference/cli/commands/aspire-terminal/ and https://aspire.dev/whats-new/aspire-13-6/ Image: https://devblogs.microsoft.com/aspire/wp-content/uploads/sites/90/2026/08/aspire-terminal-guessing-game.webp (cropped to the interactive content).

New in 13.6 and in preview: WithRepl() / withRepl() adds a REPL command to PostgreSQL, MySQL, SQL Server, MongoDB, Redis, and Valkey resources. Selecting it runs the client bundled in the container (psql, sqlcmd, mongosh, redis-cli, and so on) in the dashboard's new terminal dock, with connection details and credentials already configured, so nothing installs locally. It is opt-in because the session uses the resource's real credentials with full write access, and it works only in run mode. Only share dashboard access with trusted users. Press backtick to show or hide the dock. Hiding the dock leaves sessions running: exit the client before closing its tab. This complements the previous slide: WithTerminal() gives a console app its own terminal, while the dock and its experimental APIs let you open terminals into container and executable resources. Live companion: samples/dotnet-react-postgres already enables .WithRepl() on postgres. Open postgres > Actions > REPL, then run \connect quotesdb and SELECT id, text, author FROM quotes ORDER BY id DESC LIMIT 5; to inspect the quotes just imported. Exit with \q before closing the tab. This continues the same Quotes Board demo without starting another stack. The reference screenshot shows Redis; the live sample demonstrates the same feature with PostgreSQL. Requires Aspire 13.6, which the repository samples use (13.6.1). Transition: the same discoverable resource state and actions can also give a coding agent useful runtime context. Sources: https://devblogs.microsoft.com/aspire/whats-new-aspire-13-6/ and https://aspire.dev/dashboard/terminals/ Image: https://aspire.dev/_astro/redis-repl-dock.OdVXcskn_1CLwQQ.webp (cropped to the resource and the docked REPL).

Current guidance recommends Aspire skills first and MCP when live runtime context is needed. VS Code, Claude Code, Copilot CLI, and OpenCode can use the CLI-hosted MCP server. The former dashboard-hosted MCP server has been removed: do not look for a dashboard MCP button, HTTP endpoint, or API key. aspire agent init configures the stdio command aspire agent mcp. Separately, the dashboard AI Assistant chat UI was removed in 13.5. The supported story is an external coding agent using skills and the CLI/MCP, not an embedded dashboard chat. Tools include list_resources, list_console_logs, list_structured_logs, list_traces, execute_resource_command, search_docs, and doctor. Sources: https://aspire.dev/get-started/aspire-mcp-server/ and https://aspire.dev/get-started/aspire-skills/ and https://aspire.dev/whats-new/aspire-13-5/

Show this as setup guidance, not another required live initialization or AppHost launch; the Quotes Board is already running. aspire agent init creates configuration for the detected agent. This is .vscode/mcp.json; Claude Code uses .mcp.json instead. MCP configuration is only needed when MCP is selected; skills do not require it. The agent launches aspire agent mcp over stdio, not an HTTP connection to the dashboard. Source: https://aspire.dev/get-started/aspire-mcp-server/

The opening React/FastAPI/Redis demo proved the basic polyglot workflow, and the Quotes Board made resource commands concrete. Now ask a different question: can the same model coordinate an event bus and consumers in multiple runtimes? The event-stream demo is the only required live stack in this section; artifact publishing follows later. The samples in this branch align the AppHost SDK, core packages, client integrations, and every Aspire.Hosting.* integration on 13.6.1. Keep every Aspire package on one release: mixing package families across releases can cause MissingMethodException or TypeLoadException, including in the Go, JavaScript, and Python hosting integrations. The screenshots are official reference captures; the repository demos exercise the same resource model across C#, TypeScript, Python, Go, and Java AppHosts. Open the dashboard explicitly if VS Code does not auto-launch it. Use aspire describe to inspect resources and ordinary aspire stop to preserve persistent demo data. Source: https://aspire.dev/whats-new/aspire-13-5/

Count each sample once per language used by its authored AppHost or demo workload, not the languages inside prebuilt infrastructure images. Samples can count toward multiple bars. terminal-demo adds one to JavaScript/TS (Node REPL) and one to C# (AppHost), making 16 samples and counts 9, 8, 6, 3, 2. The bars are normalized to the maximum count, 9. Run the demos sequentially; "one dashboard experience" does not mean all 16 AppHosts must run together.

The animated diagram previews the demo and replays on each visit: readings fan out from sensor-readings to both consumers every 2 seconds, then the custom 42.5 °C / 95% reading makes the Python consumer publish an alert that reaches the dashboard through sensor-alerts. It is a simulation, not live telemetry; the PDF shows the complete static diagram. Question: can the same model coordinate asynchronous work across .NET, Python, and Node.js? Stop the Quotes Board AppHost, or the optional terminal demo if used, before starting this stack. From samples/polyglot-event-stream, start aspire run --apphost AppHost/AppHost.csproj. Show the five live sensors and Kafka topics, then publish a custom reading through the producer's POST /api/events with a unique sensorId, temperature 42.5, humidity 95, location "Demo laboratory", and the current UTC timestamp. The Python consumer receives sensor-readings, calculates aggregates, and publishes the anomaly to sensor-alerts. The Node dashboard consumes both topics. Its browser fetches /api/readings and /api/alerts every five seconds; it does not use WebSockets. Show the alert's two threshold reasons and the consumer's /api/aggregates endpoint. This proves the cross-language event pipeline; do not imply every Kafka hop is automatically part of one propagated trace. Stop this AppHost when done. Payoff: one modeled graph coordinates more than HTTP request/response. Transition to production without another internals detour: DCP runs this graph locally; a production target needs its own explicit configuration.

The target package and compute-environment resource contribute deployment pipeline steps. Only compatible workloads attach to that target. Keep this slide focused on the one addition to the model. The next slide makes the production decisions explicit before showing the tested publish path. Source: https://aspire.dev/deployment/deploy-with-aspire/

Four clicks: two placement decisions, then two runtime needs. The AppHost is the contract, but deployment is not configuration-free. Add the relevant target package/resource; only compatible workloads are attached to its compute environment. Docker Compose, Kubernetes/AKS, and Azure targets have different infrastructure, image, parameter, and credential requirements. Persistent-volume APIs are experimental in 13.5. cert-manager, Gateway API, and AGC require the corresponding target-specific configuration. Existing Azure resources can be referenced across scopes when explicitly modeled and authorized; they are not all created automatically. Sources: https://aspire.dev/deployment/deploy-with-aspire/ and https://devblogs.microsoft.com/aspire/whats-new-aspire-13-5/

This is the tested publish handoff, not an Azure deployment transcript or a timing benchmark. First verify the development run, then stop the AppHost before running the Compose output. aspire publish creates docker-compose.yaml and .env with an API_IMAGE placeholder; Docker builds and runs the image here. Validation used a session-specific Compose project name and a separate localhost-only port override; the generated Compose file was not edited. Redis retained the counter across an API restart. Redis data persistence across its own recreation is a separate storage choice. The host port is dynamic and can change on restart: rediscover it with docker compose port api 8080. Tear down with API_IMAGE=hitcounter-api:local docker compose down. Add --volumes only when intentionally deleting the demo's volume data. aspire deploy is the alternative target-driven build/apply path after the required target configuration; it does not consume the files from this publish handoff. No cloud deployment or elapsed-time claim is being made.

Use the existing recipe manager, not a new sample. Stop the previous running demo first; the recipe AppHost does not need to be running to publish artifacts. Show AddAzureContainerAppEnvironment("aca"), the Cosmos database/container, and the Angular static publishing configuration in AppHost/Program.cs. The normal development path still uses the local Cosmos emulator. Run aspire publish --apphost AppHost/AppHost.csproj --list-steps -o aspire-output/bicep --non-interactive, then the publish command shown. This is artifact generation without an Azure login or subscription selection, not a deployment. Open main.bicep to show the resource group and five infrastructure modules. Then inspect cosmos/cosmos.bicep, api/api.bicep, and frontend/frontend.bicep: Cosmos schema and managed-identity access, an internal API, and the public Angular/YARP frontend. Important boundary: main.bicep references infrastructure modules only. The API and frontend compute templates are separate stages; this is not a one-file application deployment. Image references and deployment parameters still need values. Compile with az bicep build --file aspire-output/bicep/main.bicep, then for module in aspire-output/bicep/*/*.bicep; do az bicep build --file "$module" || exit 1; done. All eight generated templates compiled locally with Bicep 0.42.1; unused-parameter warnings are nonblocking. Generation and compilation do not prove Azure deployment or production readiness. The sample README contains the complete walkthrough and generated-file map. Do not run aspire deploy during this demo: it is a separate action that would create billable resources.

We have followed the model from a mixed-language request to team workflows, messaging, and publishing. Close with a low-commitment adoption route and one concrete first experiment.

Offer this as the incremental adoption route: observability first, orchestration when the team is ready. For a first AppHost, return to the TypeScript starter command shown in Practical Setup; it is not another live demo. The detached Docker command prints a container ID, not its browser login URL; docker logs retrieves the authenticated URL. The standalone container retains browser-token authentication. Incoming OTLP is unauthenticated by default, so these mappings intentionally bind only to loopback for a local demo. Applications still need their OpenTelemetry SDK/exporter configured. Use docker stop aspire-demo-dashboard to clean up; --rm removes the stopped container. The AppHost, not the dashboard, adds service discovery and resource lifecycle. This repository's standalone-dashboard sample supplies three language workers if a complete telemetry demo is useful. 13.6 run history also works without an AppHost, but a standalone dashboard must opt in with a stable name, for example aspire dashboard run --application-name my-app --persistence Resume, so the same run survives restarts. Sources: https://aspire.dev/dashboard/standalone/ and https://aspire.dev/dashboard/security-considerations/ and https://devblogs.microsoft.com/aspire/whats-new-aspire-13-6/

Return to the opening pain: separate languages do not need separate orchestration stories. Each takeaway appears on its own click. For a concrete next step, run aspire new aspire-ts-starter, inspect one request in the dashboard, then model one existing service and its dependencies. Reusing the model does not erase the production target or turn publishing into deployment.