microsoft / microsoft/aspire

Optimize aspire start performance for TypeScript AppHosts

Open
#16,704 4 comments 0 reactions 1 assignee Claimed by @sebastienros View on GitHub
area-cli area-polyglot
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

## Summary

`aspire start` for TypeScript AppHosts has noticeable startup cost even with the real packaged Aspire CLI. We should optimize the TypeScript AppHost startup path.

This issue is about `aspire start`, not `aspire ls`. `aspire ls`/discovery was only used as a diagnostic baseline and is not the target here.

## Real CLI measurement

Tested with the `aspire` executable resolved from PATH:

```text
13.4.0-preview.1.26229.11+b40d74228739fb56a7192dabc3f032569069f809
```

Created a fresh TypeScript AppHost with:

```powershell
aspire new aspire-ts-empty --name RealCliTsApp --output --non-interactive --nologo --suppress-agent-init
```

Then measured two starts of the same app:

| Operation | Wall time |
|---|---:|
| `aspire start --isolated --format Json` (first) | ~10.8s |
| `aspire stop` | ~10.3s |
| `aspire start --isolated --format Json` (second) | ~9.5s |
| `aspire stop` | ~10.3s |

`aspire export --dashboard-url ... --include-hidden` was run after each start. For this empty TS AppHost the export zip was valid but empty (no app resources emitted telemetry), so the useful phase breakdown comes from the real CLI child logs and wall-clock timings.

## Real CLI phase breakdown

The real packaged CLI does **not** build a generated `AppHostServer.csproj` here. It uses `PrebuiltAppHostServer` and a cached bundled NuGet restore:

```text
[PrebuiltAppHostServer] Restoring 2 integration packages via bundled NuGet
[BundleNuGetService] Using cached restore ...\.aspire\packages\restore\...\libs
```

Approximate phases from the child CLI logs:

| Phase | First start | Second start |
|---|---:|---:|
| Parent overhead outside child process | ~0.40s | ~0.36s |
| AppHost discovery in child | ~5ms | ~1ms |
| Bundle/prebuilt setup | ~69ms | ~19ms |
| Cached bundled NuGet restore lookup | ~2ms | ~3ms |
| Connect until TS codegen starts | ~1.67s | ~1.72s |
| TypeScript module generation | ~98ms | ~88ms |
| `npm install` even when up to date | ~1.32s | ~1.15s |
| `npx --no-install tsx ...` launch to backchannel connected | ~4.19s | ~3.37s |
| Backchannel connected to dashboard listening | ~2.95s | ~2.65s |
| Distributed app startup within that dashboard wait | ~2.92s | ~2.59s |

## Likely optimization areas

1. Reduce the `npx --no-install tsx` launch to backchannel connection time.
- This is the largest measured warm-start phase at ~3.4-4.2s.
- Investigate whether `npx` adds avoidable process/package-resolution overhead and whether the runtime can launch `tsx` more directly.
2. Reduce the dashboard/DCP/distributed-app startup portion after the TypeScript process connects.
- This is ~2.6-2.9s in the empty app.
3. Avoid or short-circuit `npm install` when inputs prove it is unnecessary.
- It still costs ~1.1-1.3s even when npm reports everything is up to date.
4. Investigate the ~1.7s gap between beginning AppHost connection and TypeScript SDK generation starting.
- The prebuilt server is being used, but there is still noticeable time before the CLI can generate modules through RPC.
5. Add finer release-build diagnostics for `aspire start` / `aspire stop`.
- Debug CLI diagnostic spans were useful, but the real packaged CLI does not emit those spans to the dashboard.
- `aspire stop` is consistently ~10s in this tiny app and currently has too little phase detail.

## Correction from earlier profiling

Earlier debug-build profiling showed a large generated `AppHostServer.csproj` build cost. That is not representative of the real packaged CLI path and should not be treated as an optimization target for this issue.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.