AspireC4.Hosting is an Aspire extension library that generates live LikeC4 diagrams from the Aspire resource graph.
- .NET 8 or later.
- Aspire 13.4.3 or later. Aspire AppHost projects must reference both the AppHost SDK and
Aspire.Hosting.AppHost. - Docker is used by default to run the LikeC4 sidecar container.
- Optional: a local Node.js CLI runtime (
npx,pnpm,yarn,bun, ordeno) if you call.WithLocalCLI().
Add AspireC4 to the AppHost project:
dotnet add package AspireC4.Hosting
dotnet add package Aspire.Hosting.AppHostAn Aspire 13.4 AppHost project should contain the equivalent of:
<Project Sdk="Aspire.AppHost.Sdk/13.4.3">
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
<PackageReference Include="AspireC4.Hosting" />
</ItemGroup>
</Project>var builder = DistributedApplication.CreateBuilder(args);
builder.AddAspireC4();
builder.Build().Run();This writes ./likec4/gen/model.gen.c4, starts the LikeC4 server, and refreshes the diagram as the Aspire app changes.
Configure the diagram through AspireC4DiagramOptions:
| Property | Default | Description |
|---|---|---|
Title |
null |
Title shown in the LikeC4 app |
ViewTitle |
"Architecture" |
Title shown in the generated view |
ViewDescription |
null |
Optional view description |
OutputDirectory |
"./likec4/gen/" |
Directory where the generated .c4 file is written |
FileName |
"model.gen" |
Generated file name without extension |
DisableHMR |
false |
Disable Hot Module Replacement |
HMRPort |
24678 |
HMR port used by the LikeC4 server and browser |
ContainerImageTag |
null (latest) |
Pin the ghcr.io/likec4/likec4 image tag |
AutoIconsEnabled |
true |
Infer LikeC4 icons from resource type and name |
HideFromDashboard |
false |
Hide the LikeC4 sidecar from the Aspire dashboard |
DashboardLinkDisplayName |
"Architecture Diagram" |
Name used for the diagram link when hidden from the dashboard |
IncludeAspireDashboardLinks |
true |
Add Aspire dashboard links to diagram elements |
builder.AddAspireC4().WithLocalCLI();builder.AddAspireC4().WithHideFromDashboard();builder.AddAspireC4(options => options.WithHMRDisabled());The LikeC4 sidecar is excluded automatically. Use WithIncludeAspireC4InternalResource(true) if you want to inspect it.
AspireC4 supports both C# and TypeScript Aspire AppHosts. In a TypeScript AppHost, the Aspire integration exports the same diagram configuration, resource metadata, grouping, and relationship features through camel-cased asynchronous APIs. The C# registry source generator described later is not applied to TypeScript; TypeScript applications configure tags, kinds, groups, and metadata through the generated fluent API.
The Aspire CLI generates the TypeScript API surface under .aspire/modules/. Import createBuilder from the generated
Aspire module, then add AspireC4 to the builder:
import { createBuilder } from "./.aspire/modules/aspire.mjs";
const builder = await createBuilder();
await builder
.addAspireC4({
configure: async (options) => {
options
.withTitle("My distributed application")
.withViewTitle("Architecture")
.withViewDescription("Generated from the Aspire resource graph");
},
})
.configureServer(async (resource) => {
resource.withLikeC4Details({
configure: async (options) => {
options.withLabel("Architecture diagram");
},
});
});
const api = await builder.addNodeApp("api", "../api", "index.ts");
await api.withLikeC4Details({
configure: async (options) => {
options
.withLabel("API")
.withTechnology("Node.js")
.withTag("backend");
},
});
const app = await builder.build();
await app.run();Declare the integration and its Aspire dependencies in aspire.config.json:
{
"appHost": {
"path": "apphost.mts",
"language": "typescript/nodejs"
},
"sdk": {
"version": "13.4.3"
},
"packages": {
"Aspire.Hosting.JavaScript": "13.4.3",
"AspireC4.Hosting": "13.3.3"
}
}Use the AspireC4 package version appropriate for the application. The repository sample points AspireC4.Hosting at
../../src/src/AspireC4/AspireC4.csproj so it exercises the local source instead of a published package.
The sample at samples/typescript-app-host demonstrates:
- AspireC4 configuration from
apphost.mts. - Azure Redis and PostgreSQL resources running as local containers.
- Redis Commander and PgWeb dashboard resources.
- A TypeScript Node.js service with Redis and PostgreSQL references.
- LikeC4 labels, descriptions, links, icons, metadata, tags, groups, and relationships.
- Additional LikeC4 DSL and image folders from this repository's
assetsdirectory.
Prerequisites are Docker, the Aspire CLI, and a supported Node.js release (20.19+, 22.13+, or 24+). From the
repository root:
cd samples/typescript-app-host
npm ci
aspire restore
aspire startaspire restore restores the integrations declared in aspire.config.json and regenerates .aspire/modules/. Once
aspire start completes, open the Aspire dashboard URL printed by the CLI and select the LikeC4 resource or its
architecture-diagram link. The sample also exposes the node-app /health, /ping/redis, and /ping/postgres
endpoints through Aspire-assigned URLs.
For an interactive foreground session, the sample's npm script is equivalent to aspire run:
npm run devStop a background session with:
aspire stopDo not edit files under .aspire/modules/; Aspire owns and regenerates them. If the folder is missing or stale after a
pull, clean, or branch switch, run:
aspire restoreWhen adding another Aspire integration, use aspire add <package> so Aspire updates aspire.config.json and regenerates
the TypeScript API. Inspect .aspire/modules/aspire.mts to see the APIs currently available to apphost.mts.
AspireC4 includes an incremental source generator built on Purview.SourceGeneratorFramework. It can validate constant
values passed to:
.WithTag().WithKind().WithLikeC4Group().WithMetadata()
The generator injects the registry attributes and enums automatically. Do not declare or reference a separate source generator package.
Add one [LikeC4Registry] class to the AppHost assembly. Its accessibility and nesting do not matter. Values are
declared as const string fields in conventionally named nested classes:
using Aspire.Hosting.AspireC4;
[LikeC4Registry]
internal static class ArchitectureRegistry
{
public static class Tags
{
public const string External = "external";
public const string LocalDevelopment = "local-dev";
}
public static class ElementKinds
{
public const string Service = "service";
}
public static class RelationshipKinds
{
public const string Async = "async";
}
public static class Groups
{
public const string Platform = "Platform";
}
public static class MetadataKeys
{
public const string AzureSku = "Azure_SKU";
}
}Supported nested-class names are:
| Registry type | Accepted class names |
|---|---|
| Tag | Tag, Tags |
| Element kind | ElementKind, ElementKinds, Element, Elements |
| Relationship kind | RelationshipKind, RelationshipKinds, Relationship, Relationships |
| Group | Group, Groups |
| Metadata key | MetadataKey, MetadataKeys |
Use the constants at call sites to make refactoring safe:
builder.AddProject<Projects.Api>("api")
.WithTag(ArchitectureRegistry.Tags.External)
.WithKind(ArchitectureRegistry.ElementKinds.Service)
.WithLikeC4Group(ArchitectureRegistry.Groups.Platform)
.WithMetadata(ArchitectureRegistry.MetadataKeys.AzureSku, "Standard_LRS");For a flat registry, annotate each constant with [KnownType]:
[LikeC4Registry]
internal static class ArchitectureRegistry
{
[KnownType(LikeC4RegistryType.Tag)]
public const string External = "external";
[KnownType(LikeC4RegistryType.Group, Strict = LikeC4Severity.Warning)]
public const string Platform = "Platform";
}Do not declare the same registry type using both a named nested class and [KnownType] fields. Doing so produces
ASPIREC4005.
Without an explicit strict setting, a registry class enables suggestion-level validation. Severity can be configured at three levels, from broadest to most specific:
- The
AspireC4StrictMSBuild property. [LikeC4Registry(Strict = ...)]for the registry.[Severity(...)]on a named nested class, orKnownType.Stricton an individual field.
[LikeC4Registry(Strict = LikeC4Severity.Warning)]
internal static class ArchitectureRegistry
{
[Severity(LikeC4Severity.Error)]
public static class Tags
{
public const string External = "external";
}
[KnownType(LikeC4RegistryType.Group, Strict = LikeC4Severity.Off)]
public const string UnvalidatedGroup = "Temporary";
}LikeC4Severity supports Inherit, Off, Suggestion, Warning, and Error.
The project-wide setting can be placed in the AppHost project or Directory.Build.props:
<PropertyGroup>
<AspireC4Strict>warning</AspireC4Strict>
</PropertyGroup>Accepted AspireC4Strict values are:
| Value | Behavior |
|---|---|
off or an unset/unknown value |
Disables DSL-file strict validation |
suggestion |
Reports undeclared DSL values as suggestions |
warning |
Reports undeclared DSL values as warnings |
error, true, yes, or all |
Reports undeclared DSL values as errors |
allincludingmetadata |
Error-level validation including metadata keys |
Metadata-key comparison is case-insensitive and normalizes punctuation and whitespace to underscores. For example,
Azure SKU, azure sku, and Azure_SKU identify the same key.
To disable all AspireC4 source-generator diagnostics while retaining the injected registry types:
<PropertyGroup>
<DisableAspireC4SourceGenerator>true</DisableAspireC4SourceGenerator>
</PropertyGroup>Add .c4 or .likec4 specification files as compiler additional files, then set AspireC4Strict:
<ItemGroup>
<AdditionalFiles Include="likec4/**/*.c4" />
<AdditionalFiles Include="likec4/**/*.likec4" />
</ItemGroup>
<PropertyGroup>
<AspireC4Strict>warning</AspireC4Strict>
</PropertyGroup>Tags, element kinds, and relationship kinds in specification blocks are merged with registry-class definitions.
| ID | Meaning |
|---|---|
ASPIREC4001 |
A tag passed to .WithTag() is undeclared |
ASPIREC4002 |
An element or relationship kind passed to .WithKind() is undeclared |
ASPIREC4003 |
More than one class in the assembly has [LikeC4Registry] |
ASPIREC4004 |
A group passed to .WithLikeC4Group() is undeclared |
ASPIREC4005 |
A registry type uses both a nested class and [KnownType] fields |
ASPIREC4006 |
A metadata key passed to .WithMetadata() is undeclared |
The source generator now uses the current Purview.SourceGeneratorFramework incremental APIs. Existing applications
should review the following changes when upgrading:
- Aspire AppHost dependency is explicit. Aspire 13.4 AppHosts must reference
Aspire.Hosting.AppHost; relying on the AppHost SDK alone producesASPIRE002. - Only one registry class is supported per assembly. Merge multiple
[LikeC4Registry]classes into one class. - Registry declaration styles cannot be mixed per type. For example, choose either a
Tagsnested class or[KnownType(LikeC4RegistryType.Tag)]fields. Mixing both now producesASPIREC4005. - Strict settings are severity-based. Replace older boolean-only assumptions with
suggestion,warning,error,all, orallincludingmetadata.trueremains accepted as an alias for error-level validation. - Metadata validation is opt-in at the global level. Use
allincludingmetadata, or apply an explicit metadata severity through[Severity]/[KnownType]. Plainalldoes not validate metadata keys. - Generated source files are split by type. The generator now emits
LikeC4RegistryAttribute.g.cs,KnownTypeAttribute.g.cs,SeverityAttribute.g.cs,LikeC4RegistryType.g.cs, andLikeC4Severity.g.csinstead of a combinedLikeC4RegistryAttributes.g.cs. This affects generator snapshot tests and tooling that inspected hint names; normal application source code is unaffected. - Do not define generated registry types manually. Remove compatibility copies of
LikeC4RegistryAttribute,KnownTypeAttribute,SeverityAttribute,LikeC4RegistryType, orLikeC4Severityto avoid duplicate-type errors. - Generator packaging is automatic. Consumers should reference only
AspireC4.Hosting; remove direct references toAspireC4.SourceGeneratorsorPurview.SourceGeneratorFrameworkthat were added solely to make the AspireC4 generator run. - TypeScript APIs are generated by Aspire. TypeScript AppHosts import from
.aspire/modules/aspire.mjs; generated files must not be copied between projects or edited manually. Runaspire restoreafter upgrading AspireC4 so the exported API matches the installed integration version.