Skip to content
Docs Try Aspire

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.

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.

When you run a TypeScript AppHost, the Aspire CLI orchestrates two processes:

  • Guest: your apphost.ts process, 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
  1. The CLI prepares the host process with the required hosting packages.
  2. The ATS scanner inspects assemblies for exports and generates the TypeScript SDK into .modules/.
  3. The CLI starts the host process and creates the local socket or pipe endpoint.
  4. The CLI starts the guest process and passes connection details through environment variables.
  5. The guest connects and invokes capabilities such as createBuilder, addRedis, build, and run.
  6. The host orchestrates resources, starts the dashboard, and manages the application lifecycle.

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.

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.

CategoryDescriptionSerialization
Primitivestring, int, bool, double, and similar scalar typesJSON native values
Enum.NET enum typesString member names
HandleOpaque references to host-side objectsJSON handle envelopes
DTOData transfer objects marked for exportJSON objects
CallbackGuest-provided delegate functionsCallback identifiers
ArrayImmutable collectionsJSON arrays
List / dictionaryMutable collectionsHandles for properties, JSON for parameters
.NET typeTypeScript representation
PrimitivesNative TypeScript primitives
EnumsString literal unions
Resource typesTyped handle objects with fluent methods
DTOsInterfaces serialized as JSON
CollectionsArrays and Record<string, T>
DelegatesAsync 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.

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

The TypeScript SDK is generated from hosting integration assemblies. When you add an integration with aspire add, the CLI:

  1. Loads the integration assembly.
  2. Scans exported methods and types.
  3. Applies ATS rules, including polymorphism flattening.
  4. 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.

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.

ConceptC#TypeScript
Create builderDistributedApplication.CreateBuilder(args)await createBuilder()
Add resourcebuilder.AddRedis("cache")await builder.addRedis("cache")
Reference.WithReference(db).withReference(db)
Wait for.WaitFor(api).waitFor(api)
Build and runbuilder.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.