Gå til indhold
Docs Try Aspire
Docs Try

TypeScript AppHost project structure

Dette indhold er ikke tilgængeligt i dit sprog endnu.

When you create a TypeScript AppHost with aspire new or aspire init --language typescript, the CLI scaffolds a project with the following structure:

  • Mappemy-apphost/
    • Mappe.modules/ Generated TypeScript SDK (do not edit)
      • aspire.ts
      • base.ts
      • transport.ts
    • apphost.ts Your AppHost entry point
    • aspire.config.json Aspire configuration
    • package.json
    • tsconfig.json

The aspire.config.json file is the central configuration for your AppHost. It replaces the older .aspire/settings.json and apphost.run.json files.

aspire.config.json
{
"appHost": {
"path": "apphost.ts",
"language": "typescript/nodejs"
},
"packages": {
"Aspire.Hosting.JavaScript": "13.3.0"
},
"profiles": {
"https": {
"applicationUrl": "https://localhost:17127;http://localhost:15118",
"environmentVariables": {
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21169",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22260"
}
}
}
}
SectionDescription
appHost.pathPath to your AppHost entry point (apphost.ts)
appHost.languageLanguage runtime (typescript/nodejs)
packagesHosting integration packages and their versions. Added automatically by aspire add.
profilesLaunch profiles with dashboard URLs and environment variables

When you run aspire add, the CLI adds the package to the packages section and regenerates the TypeScript SDK:

Add an integration
aspire add redis

This updates aspire.config.json:

aspire.config.json
{
"packages": {
"Aspire.Hosting.JavaScript": "13.3.0",
"Aspire.Hosting.Redis": "13.3.0"
}
}

You can reference a local hosting integration project by using a .csproj path instead of a version:

aspire.config.json
{
"packages": {
"MyIntegration": "../src/MyIntegration/MyIntegration.csproj"
}
}

See Multi-language integrations for details on building hosting integrations that work with TypeScript AppHosts.

The .modules/ directory contains the generated TypeScript SDK. It’s created and updated automatically by the Aspire CLI — do not edit these files.

FilePurpose
aspire.tsGenerated typed API for all your installed integrations
base.tsBase types and handle infrastructure
transport.tsJSON-RPC transport layer

The SDK regenerates when:

  • You run aspire add to add or update an integration
  • You run aspire run or aspire start and the package list has changed
  • You run aspire restore to manually regenerate

Your apphost.ts imports from this SDK:

apphost.ts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.modules/aspire.js';

The entry point for your AppHost. This is where you define your application’s resources and their relationships:

apphost.ts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.modules/aspire.js';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const cache: RedisResource
cache
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRedis(name: string, options?: {
port?: number;
password?: string | ParameterResource;
}): RedisResource (+1 overload)

Adds a Redis container resource

addRedis
("cache");
const
const api: NodeAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addNodeApp(name: string, appDirectory: string, scriptPath: string): NodeAppResource

Adds a Node.js application resource

addNodeApp
("api", "./api", "src/index.ts")
.
ExecutableResource.withHttpEndpoint(options?: {
port?: number;
targetPort?: number;
name?: string;
env?: string;
isProxied?: boolean;
} | undefined): NodeAppResource (+1 overload)

Adds an HTTP endpoint

withHttpEndpoint
({
env?: string | undefined
env
: "PORT" })
.
ExecutableResource.withReference(source: EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): NodeAppResource (+2 overloads)

Adds a reference to another resource

withReference
(
const cache: RedisResource
cache
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

The Aspire CLI automatically detects which package manager your TypeScript AppHost uses by inspecting lock files and the packageManager field in package.json. The following package managers are supported:

Package managerLock file detectedNotes
npmpackage-lock.jsonDefault; no extra setup required
pnpmpnpm-lock.yaml
Yarn (v4+)yarn.lockMust be Yarn 4 or later (Berry)
Bunbun.lock / bun.lockb

The scaffolded package.json includes convenience scripts and the required Node.js version:

package.json
{
"name": "my-apphost",
"private": true,
"type": "module",
"scripts": {
"dev": "aspire run",
"build": "tsc",
"lint": "eslint apphost.ts"
},
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
}
}

The dev script means you can also start your AppHost with npm run dev (or the equivalent for your toolchain, for example bun run dev or pnpm run dev).

The Aspire CLI automatically detects which Node-compatible package manager your project uses and adjusts install and run commands accordingly. The following toolchains are supported: npm (default), Bun, Yarn, and pnpm.

The CLI resolves the toolchain by inspecting the AppHost directory and its parent directories (up to eight levels). It checks, in order:

  1. The packageManager field in package.json — for example, "packageManager": "pnpm@9.0.0".
  2. Lockfiles: bun.lock or bun.lockb → Bun; pnpm-lock.yaml → pnpm; yarn.lock, .yarnrc.yml, or a .yarn/ directory → Yarn.
  3. If nothing is found, npm is used as the default.

The search walks up parent directories, so a workspace-level packageManager setting or lockfile is picked up automatically by nested AppHosts.

The recommended way to pin the toolchain is with the packageManager field in package.json, which Aspire uses for toolchain detection. This field is also used by Node.js Corepack for package managers such as Yarn and pnpm:

No extra configuration is required — npm is the default.

Alternatively, committing a toolchain-specific lockfile (pnpm-lock.yaml, yarn.lock, bun.lock, etc.) is sufficient for detection.

When a non-npm toolchain is detected, the CLI substitutes the matching commands:

ToolchainInstall commandExecute commandWatch command
npmnpm installnpx tsx ...npx nodemon ...
pnpmpnpm installpnpm exec tsx ...pnpm exec nodemon ...
Yarnyarn installyarn exec tsx ...yarn exec nodemon ...
Bunbun installbun run {appHostFile}bun --watch run {appHostFile}

The aspire doctor command checks that the required JavaScript toolchain executable is available. If Bun, Yarn, or pnpm is detected but not installed, the command reports an error with install guidance.

Aspire CLI
aspire doctor

Before starting a TypeScript AppHost, the Aspire CLI runs tsc --noEmit to check for type errors to prevent the dashboard and resources from starting in a partially broken state. If your AppHost has TypeScript compile errors, aspire run and aspire publish stop before the AppHost launches and display the diagnostic output:

apphost.ts(22,7): error TS2322: Type 'string' is not assignable to type 'number'.

When you use aspire run in watch mode, the TypeScript validation is embedded in the nodemon restart command. The watcher can still start even if there are initial type errors — it will recover automatically as you edit and save files that fix the errors.