Multi-language architecture
Aspire supports writing AppHosts in multiple languages. While the orchestration engine is built on .NET, a guest/host architecture allows AppHosts written in TypeScript and other languages in the future to access Aspire integrations, service discovery, and the dashboard.
Why a shared backend
Section titled “Why a shared backend”Aspire’s hosting integrations and deployment publishers are written in .NET and have already accumulated the runtime behavior needed for local orchestration, diagnostics, and publishing. Rewriting those integrations for every guest language would duplicate a large amount of behavior and significantly increase maintenance cost.
Instead, guest languages only declare resources such as addRedis, addPostgres, and withReference, while the .NET host handles orchestration concerns such as starting containers, wiring service discovery, running health checks, and generating deployment artifacts. The trade-off is a local IPC hop, which is much cheaper than maintaining the same integration surface independently in multiple languages.
Guest/host model
Section titled “Guest/host model”When you run a TypeScript AppHost, the Aspire CLI orchestrates two processes:
- Guest: your
apphost.tsprocess, running in Node.js - Host: the Aspire orchestration server, running on .NET
The guest communicates with the host via JSON-RPC over a local transport: Unix sockets on macOS and Linux, and named pipes on Windows. Your code calls methods such as addRedis() or withReference(), and the generated SDK translates those calls into RPC requests.
flowchart TB
subgraph Guest["Guest Process (Node.js)"]
TS["apphost.ts"]
SDK["Generated SDK (.modules/)"]
Client["JSON-RPC Client"]
TS --> SDK --> Client
end
subgraph Host["Host Process (Aspire Server)"]
RPC["JSON-RPC Server"]
Dispatcher["Capability Dispatcher"]
Integrations["Hosting Integrations"]
RPC --> Dispatcher --> Integrations
end
subgraph Managed["Managed Resources"]
Dashboard["Dashboard"]
Containers["Containers"]
Discovery["Service Discovery"]
end
Client <-->|"Local transport"| RPC
Integrations --> Dashboard & Containers & Discovery
Startup sequence
Section titled “Startup sequence”- The CLI prepares the host process with the required hosting packages.
- The ATS scanner inspects assemblies for exports and generates the TypeScript SDK into
.modules/. - The CLI starts the host process and creates the local socket or pipe endpoint.
- The CLI starts the guest process and passes connection details through environment variables.
- The guest connects and invokes capabilities such as
createBuilder,addRedis,build, andrun. - The host orchestrates resources, starts the dashboard, and manages the application lifecycle.
Token-based authentication
Section titled “Token-based authentication”The guest process authenticates to the host with a one-time token generated for that session and passed through environment variables at startup. The local transport is also protected by operating system file permissions, so only processes running as the same user can connect. There are no public network ports involved in guest-to-host communication.
Aspire Type System
Section titled “Aspire Type System”The Aspire Type System, or ATS, is the contract that bridges .NET and guest languages. Every exported type that crosses the boundary gets a portable type identity derived from its assembly and type name.
Type categories
Section titled “Type categories”| Category | Description | Serialization |
|---|---|---|
| Primitive | string, int, bool, double, and similar scalar types | JSON native values |
| Enum | .NET enum types | String member names |
| Handle | Opaque references to host-side objects | JSON handle envelopes |
| DTO | Data transfer objects marked for export | JSON objects |
| Callback | Guest-provided delegate functions | Callback identifiers |
| Array | Immutable collections | JSON arrays |
| List / dictionary | Mutable collections | Handles for properties, JSON for parameters |
How ATS maps to TypeScript
Section titled “How ATS maps to TypeScript”| .NET type | TypeScript representation |
|---|---|
| Primitives | Native TypeScript primitives |
| Enums | String literal unions |
| Resource types | Typed handle objects with fluent methods |
| DTOs | Interfaces serialized as JSON |
| Collections | Arrays and Record<string, T> |
| Delegates | Async callback functions |
Resource types are passed by handle. The actual instance remains in the host process, while the TypeScript SDK keeps a reference and dispatches method calls as JSON-RPC requests.
Polymorphism flattening
Section titled “Polymorphism flattening”.NET APIs rely on inheritance, interfaces, and generics. Guest SDKs do not need to expose that full shape directly. During scanning, ATS flattens the exported type system so the generated guest API is easier to consume:
- Concrete types receive the full set of applicable capabilities.
- Interface relationships are expanded into directly callable members.
- Generic constraints are resolved into exportable concrete surfaces.
That flattening means a resource such as RedisResource can expose fluent methods from shared interfaces alongside Redis-specific APIs without requiring guest languages to model the original inheritance tree.
SDK generation
Section titled “SDK generation”The TypeScript SDK is generated from hosting integration assemblies. When you add an integration with aspire add, the CLI:
- Loads the integration assembly.
- Scans exported methods and types.
- Applies ATS rules, including polymorphism flattening.
- Emits typed TypeScript wrappers into
.modules/.
This keeps the SDK in sync with the .NET implementation. Integration authors do not hand-write TypeScript bindings; they export their .NET APIs and the CLI generates the guest surface automatically.
If you’re building a hosting integration and want it to work with TypeScript AppHosts, see Multi-language integrations.
Same model, different syntax
Section titled “Same model, different syntax”The AppHost model is the same regardless of language. A TypeScript AppHost defines the same resources, references, and dependency graph as a C# AppHost. The difference is the authoring syntax.
| Concept | C# | TypeScript |
|---|---|---|
| Create builder | DistributedApplication.CreateBuilder(args) | await createBuilder() |
| Add resource | builder.AddRedis("cache") | await builder.addRedis("cache") |
| Reference | .WithReference(db) | .withReference(db) |
| Wait for | .WaitFor(api) | .waitFor(api) |
| Build and run | builder.Build().Run() | await builder.build().run() |
The resulting dashboard, service discovery behavior, health checks, and deployment artifacts come from the same host-side orchestration engine.
See also
Section titled “See also”- Build your first app — get started with a TypeScript AppHost
- Resource model — understand how Aspire models resources and relationships
- Multi-language integrations — make your integration work with multi-language AppHosts