Set up Rust apps in the AppHost

このコンテンツはまだ日本語訳がありません。

Rust logo

This article is the reference for the Aspire Rust hosting integration. It enumerates the AppHost APIs — with examples for both apphost.mts and AppHost.cs — that you use to model Rust apps in your AppHost: Cargo packages that Aspire runs with cargo run, the Cargo options that select features, binaries, examples, workspace members, profiles, and target triples, and the arguments that Aspire passes to your program. It also describes how Aspire configures certificate trust for Rust apps, debugs them, and builds them into container images when you publish.

If you’re new to the Rust integration, start with Get started with the Rust integration. For how other resources call your Rust apps — and how your Rust apps read the configuration that Aspire injects and send telemetry to the dashboard — see Connect to Rust apps. If you’re moving from the Community Toolkit package, see Migrate from the Community Toolkit.

To start modeling Rust apps in your AppHost, install the 📦 Aspire.Hosting.Rust NuGet package:

Terminal
aspire add rust

Learn more about aspire add in the command reference.

This updates your aspire.config.json with the Rust hosting integration package:

aspire.config.json
{
"packages": {
"Aspire.Hosting.Rust": "13.6.0-preview.1.26479.8"
}
}

Use AddRustAppaddRustApp to add a Rust app. The app directory is resolved relative to the AppHost directory. It’s Cargo’s working directory and, when you publish, the build context of the app’s container image. Cargo finds the app’s Cargo.toml by searching from that directory, as it does when you run cargo in a terminal.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../api');
await
const api: RustAppResource
api
.
ExecutableResource.withHttpEndpoint(options?: {
port?: number;
targetPort?: number;
name?: string;
env?: string;
isProxied?: boolean;
} | undefined): RustAppResource (+1 overload)

Adds an HTTP endpoint

withHttpEndpoint
({
env?: string | undefined
env
: 'PORT' });
await
const api: RustAppResource
api
.
ExecutableResource.withHttpHealthCheck(options?: {
path?: string;
statusCode?: number;
endpointName?: string;
} | undefined): RustAppResource (+1 overload)

Adds a health check to the resource which is mapped to a specific endpoint.

withHttpHealthCheck
({
path?: string | undefined
path
: '/health' });
const
const frontend: NodeAppResource
frontend
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addNodeApp(name: string, appDirectory: string, scriptPath: string): NodeAppResource

Adds a node application to the application model. Node should be available on the PATH.

addNodeApp
('frontend', '../frontend', 'server.js');
await
const frontend: NodeAppResource
frontend
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): NodeAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const api: RustAppResource
api
);
await
const frontend: NodeAppResource
frontend
.
ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): NodeAppResource

Waits for another resource to be ready

waitFor
(
const api: RustAppResource
api
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

In the preceding example, WithHttpEndpointwithHttpEndpoint adds an HTTP endpoint to the api app and passes its port to the app in the PORT environment variable, and WithHttpHealthCheckwithHttpHealthCheck makes Aspire poll the app’s /health endpoint. The frontend app uses WithReferencewithReference to receive the api app’s URL, and WaitForwaitFor to start only after api is healthy.

When a Rust app starts, Aspire:

  • Runs cargo run in the app directory, with the Cargo options and program arguments that you configure. Cargo builds the app before it runs it, and the build output appears in the app’s console logs in the dashboard.
  • Keeps Cargo’s defaults for a local run: a dev profile build, and a Cargo.lock file that Cargo can update. Publishing uses different defaults, as described in Publish Rust apps.
  • Sets the standard OpenTelemetry environment variables, which point at the dashboard. The app sends telemetry only when it uses the OpenTelemetry SDK for Rust. For details, see Send telemetry to the dashboard.
  • Configures the app to trust the development certificate, as described in Configure certificate trust.

AddRustApp doesn’t add an endpoint, because a Rust program doesn’t read its port from the environment on its own. Add an endpoint with WithHttpEndpoint, name the environment variable that carries the port with its env parameter, and make the app listen on that port. Listen on all interfaces rather than on 127.0.0.1, so the app is also reachable when it runs in a container after you publish. For example, with axum:

src/main.rs
use std::net::SocketAddr;
use axum::{routing::get, Router};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let port = std::env::var("PORT")
.ok()
.and_then(|value| value.parse::<u16>().ok())
.unwrap_or(8080);
let app = Router::new().route("/health", get(|| async { "healthy" }));
let listener = tokio::net::TcpListener::bind(SocketAddr::from(([0, 0, 0, 0], port))).await?;
axum::serve(listener, app).await?;
Ok(())
}

Cargo separates its own options from the arguments of the program that it runs with --, so Aspire configures the two kinds of arguments separately. Use the WithCargo* methods for Cargo, and WithArgswithArgs for your program. Aspire adds the -- separator.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../api');
await
const api: RustAppResource
api
.
RustAppResource.withCargoFeatures(features: string[]): RustAppResource

Adds cargo features for the Rust application.

withCargoFeatures
(['postgres', 'metrics']);
await
const api: RustAppResource
api
.
RustAppResource.withCargoArgs(args: string[]): RustAppResource

Adds command-line arguments to the cargo command used by a Rust application.

withCargoArgs
(['--no-default-features']);
await
const api: RustAppResource
api
.
ExecutableResource.withArgs(args: string[]): RustAppResource

Adds arguments to be passed to a resource that supports arguments when it is launched.

withArgs
(['--log-format', 'json']);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

When you run the AppHost, the preceding example starts the app with the following command:

Command
cargo run --features postgres,metrics --no-default-features -- --log-format json

Each of the following methods adds a Cargo option. Aspire places the options in the order of the table, before the arguments that you add with WithCargoArgs(params string[] args)withCargoArgs(args: string[]):

MethodCargo optionDescription
WithCargoFeatureswithCargoFeatures--featuresEnables features. Repeated calls add features in call order.
WithCargoBinTargetwithCargoBinTarget--binSelects one of the package’s binary targets.
WithCargoExamplewithCargoExample--exampleRuns an example instead of a binary.
WithCargoPackagewithCargoPackage--packageSelects a workspace member.
WithCargoManifestPathwithCargoManifestPath--manifest-pathBuilds from a Cargo.toml file other than the one that Cargo finds from the app directory, such as a workspace member’s manifest. To publish, the path must be relative to the app directory and inside it.
WithCargoTargetwithCargoTarget--targetBuilds for a target triple, such as x86_64-unknown-linux-musl.
WithCargoLockedwithCargoLocked--lockedFails the build rather than updating Cargo.lock. Pass false to turn off the publishing default.
WithCargoProfilewithCargoProfile--profileBuilds with a named profile. It takes precedence over WithCargoReleaseBuildwithCargoReleaseBuild, because Cargo rejects --profile together with --release.
WithCargoReleaseBuildwithCargoReleaseBuild--releaseBuilds with the release profile. Pass false to turn off the publishing default.

Aspire passes the values of WithCargoArgs to Cargo without interpreting them. Debugging and publishing work out which binary Cargo produces from the methods in the preceding table alone, so select the package, binary, example, manifest, profile, and target triple with those methods rather than with WithCargoArgs. In C#, another overload of WithCargoArgs takes a callback that computes Cargo arguments when the app starts.

A Cargo package can contain several binaries and examples, and a Cargo workspace can contain several packages. Aspire reads the layout with cargo metadata to find the binary that the app runs, which the debugger launches and the published image copies. It selects:

  1. The example that you select with WithCargoExample.
  2. The binary that you select with WithCargoBinTarget.
  3. The package’s default-run binary, when its Cargo.toml file sets one.
  4. The package’s only binary.

When a package has more than one binary and no default-run setting, select one with WithCargoBinTarget. When the app directory is a workspace whose default members include more than one package with a binary, select the package with WithCargoPackage. Library-only members don’t count, so an app crate beside library crates needs no extra configuration.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const worker: RustAppResource
worker
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('worker', '../services');
await
const worker: RustAppResource
worker
.
RustAppResource.withCargoPackage(packageName: string): RustAppResource

Configures the workspace package to build and run.

withCargoPackage
('jobs');
await
const worker: RustAppResource
worker
.
RustAppResource.withCargoBinTarget(binName: string): RustAppResource

Configures the binary target to run for Rust applications that declare more than one.

withCargoBinTarget
('worker');
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

Use WithEnvironmentwithEnvironment to set environment variables on a Rust app, such as RUST_LOG, which the env_logger crate and the EnvFilter of the tracing-subscriber crate read, and RUST_BACKTRACE:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../api');
await
const api: RustAppResource
api
.
ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): RustAppResource

Sets an environment variable

withEnvironment
('RUST_LOG', 'info');
await
const api: RustAppResource
api
.
ExecutableResource.withEnvironment(name: string, value: string | IResourceWithConnectionString | IValueProvider): RustAppResource

Sets an environment variable

withEnvironment
('RUST_BACKTRACE', '1');
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

Cargo runs in the same environment, so build settings such as RUSTFLAGS and CARGO_* variables that you set this way apply to the build as well as to the program. When VS Code debugs the app, Aspire builds it with the same environment.

Aspire configures Rust apps to trust the development certificate with the default Append trust scope. It sets the SSL_CERT_DIR environment variable to a directory that contains the development certificate. OpenSSL — which the native-tls crate uses on Linux — reads that variable, and so does the rustls-native-certs crate, which clients such as tonic with its tls-native-roots feature use to load their trusted certificates. When SSL_CERT_DIR or SSL_CERT_FILE is set, rustls-native-certs loads certificates only from those locations, instead of from the operating system’s certificate store.

On Linux, Aspire also adds the system’s certificate directories — or the directories in the AppHost’s own SSL_CERT_DIR — to the variable, so these clients trust both the development certificate and public certificate authorities. On Windows and macOS, unless the AppHost’s environment sets SSL_CERT_DIR, the variable contains only Aspire’s certificate directory, so clients that use rustls-native-certs trust the development certificate but reject certificates from public certificate authorities. If a Rust app also calls public HTTPS endpoints, set its trust scope to System with WithCertificateTrustScopewithCertificateTrustScope. Aspire then also sets SSL_CERT_FILE to a bundle that contains the system’s root certificates together with the development certificate:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
,
type CertificateTrustScope = "None" | "Append" | "Override" | "System"
const CertificateTrustScope: {
readonly None: "None";
readonly Append: "Append";
readonly Override: "Override";
readonly System: "System";
}

Enum Aspire.Hosting.ApplicationModel.CertificateTrustScope

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../api');
await
const api: RustAppResource
api
.
ExecutableResource.withCertificateTrustScope(scope: CertificateTrustScope): RustAppResource

Sets the certificate trust scope

withCertificateTrustScope
(
const CertificateTrustScope: {
readonly None: "None";
readonly Append: "Append";
readonly Override: "Override";
readonly System: "System";
}

Enum Aspire.Hosting.ApplicationModel.CertificateTrustScope

CertificateTrustScope
.
type System: "System"
System
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

Clients that use the operating system’s certificate store instead, such as native-tls on Windows and macOS, ignore these variables and trust the development certificate when it’s trusted on your machine. Clients that use the built-in certificates of the webpki-roots crate never trust the development certificate.

For more information, see Certificate trust configuration.

To debug Rust apps, use the standard debugging flow of the Aspire VS Code extension. Debugging is enabled for every app that you add with AddRustApp.

When the debugger launches a Rust app, VS Code first builds it with cargo build, using the Cargo options that cargo run would use and the app’s environment variables. It then launches the binary that the build produces under a native debugger, with the arguments that you add with WithArgs and the app’s environment variables. Aspire finds the binary with cargo metadata, as described in Select the binary to run, so the debugged binary is the same one that cargo run would run and that a published image contains.

The debugger depends on your platform:

PlatformDebuggerVS Code extension
WindowsThe Visual Studio debugger (cppvsdbg)C/C++
Linux and macOSLLDBCodeLLDB

On Windows, if the C/C++ extension isn’t installed but CodeLLDB is, VS Code uses CodeLLDB. Apps that target a Windows GNU toolchain, such as x86_64-pc-windows-gnu, produce debug information that the Visual Studio debugger can’t read, so they need CodeLLDB.

When you build for a target triple, select it with WithCargoTarget, or with a CARGO_BUILD_TARGET environment variable that you set on the app, so that Aspire finds the binary under the target’s directory. A [build] target setting in a .cargo/config.toml file isn’t taken into account.

On macOS, CodeLLDB can debug a Rust process only when the macOS developer tools security policy permits it. This policy is separate from the Developer Mode setting for iOS devices. To check the policy, run:

Terminal
/usr/sbin/DevToolsSecurity -status

If the command reports Developer mode is currently disabled, enable it:

Terminal
sudo /usr/sbin/DevToolsSecurity -enable

macOS prompts you to authenticate as an administrator. Run /usr/sbin/DevToolsSecurity -status again to confirm that developer mode is enabled. Enabling developer mode addresses this prerequisite only; it doesn’t resolve every debugger failure.

When you run aspire publish or aspire deploy, Aspire packages each Rust app as a container image. If the app directory contains a Dockerfile, Aspire uses it as-is. Otherwise, Aspire generates a multi-stage Dockerfile that:

  • Builds the app inside the image with cargo build and the app’s Cargo options, so the app is never compiled on your machine. Aspire still runs cargo metadata on your machine to find the app’s binary, so publishing needs Cargo too. If the app pins a toolchain with a rust-toolchain.toml file, rustup installs it in the build stage. BuildKit cache mounts keep Cargo’s registry and the build’s target directory between builds.
  • Adds --release, unless you pass false to WithCargoReleaseBuild or select a profile with WithCargoProfile. It also adds --locked when the app directory contains a Cargo.lock file, unless you pass false to WithCargoLocked, so the image builds only the dependency versions that you committed.
  • Runs the binary on an Alpine image as an unprivileged app user, with the binary at /app/<binary name> as the container’s entry point.
  • Excludes target directories, .git, .env files, and other files that the build doesn’t need from the build context, unless the app directory has its own .dockerignore file.

The app directory is the build context, so everything that the build needs must be inside it, including a manifest that you select with WithCargoManifestPath. A Cargo --config argument that appears to contain credentials, such as a registry token, makes publishing fail, because a generated Dockerfile would store it in the image. To build with private registry credentials, author a Dockerfile that passes them with a BuildKit secret mount.

For more information about publishing, see Aspire deployment.

A crate that inherits settings from its workspace, such as version.workspace = true, or that depends on sibling crates by path, needs the whole workspace in the build context. Use the workspace root as the app directory, and select the crate with WithCargoPackage:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../services');
await
const api: RustAppResource
api
.
RustAppResource.withCargoPackage(packageName: string): RustAppResource

Configures the workspace package to build and run.

withCargoPackage
('api');
await
const api: RustAppResource
api
.
ExecutableResource.withHttpEndpoint(options?: {
port?: number;
targetPort?: number;
name?: string;
env?: string;
isProxied?: boolean;
} | undefined): RustAppResource (+1 overload)

Adds an HTTP endpoint

withHttpEndpoint
({
env?: string | undefined
env
: 'PORT' });
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

The generated Dockerfile builds on docker.io/library/rust:1.97-alpine3.24 and runs on docker.io/library/alpine:3.24. Both images use musl. To use other images, such as mirrors in your own registry or images for another target, set both in a single call to WithDockerfileBaseImagewithDockerfileBaseImage, because each call replaces the images that earlier calls set:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../api');
await
const api: RustAppResource
api
.
ExecutableResource.withDockerfileBaseImage(options?: {
buildImage?: string;
runtimeImage?: string;
} | undefined): RustAppResource (+1 overload)

Configures custom base images for generated Dockerfiles.

withDockerfileBaseImage
({
buildImage?: string | undefined
buildImage
: 'myregistry.azurecr.io/rust-armv7-build:1.97',
runtimeImage?: string | undefined
runtimeImage
: 'myregistry.azurecr.io/armv7-runtime:latest',
});
if (await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.executionContext: PropertyAccessor<DistributedApplicationExecutionContext>

Execution context for this invocation of the AppHost.

executionContext
.
DistributedApplicationExecutionContext.isPublishMode: () => Promise<boolean>

Returns true if the current operation is publishing.

isPublishMode
()) {
await
const api: RustAppResource
api
.
RustAppResource.withCargoTarget(target: string): RustAppResource

Configures the target triple cargo builds for.

withCargoTarget
('armv7-unknown-linux-gnueabihf');
}
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

WithDockerfileBaseImage affects only the published image, but WithCargoTarget also applies when you run the AppHost. Cargo then builds the app for the selected target on your machine and runs the result, which works only when your machine can build for that target and run its binaries. For that reason, the preceding example selects the target only in publish mode.

When you select a target triple with WithCargoTarget, the generated Dockerfile installs the target’s standard library with rustup target add, and builds the image for the matching platform: linux/amd64 for x86_64 targets, linux/arm64 for aarch64 targets, linux/386 for 32-bit x86 targets, and linux/arm for 32-bit ARM targets. The default images support only x86_64 and aarch64 musl targets:

  • A 32-bit musl target, such as armv7-unknown-linux-musleabihf, needs a custom build image, but can keep the default runtime image.
  • A target for another ABI, such as a gnu target, needs both a custom build image and a custom runtime image.
  • A non-Linux target, or a Linux target for another architecture, needs an authored Dockerfile.

Aspire doesn’t install a linker or other cross-compilation tools, so a custom build image must already support the target. Keep the target, the build image, and the runtime image compatible with each other.

The generated Dockerfile can copy files that another resource produces, such as a frontend’s build output, into the Rust app’s image. Call PublishWithContainerFilespublishWithContainerFiles on the Rust app with the source resource and a destination path. A relative destination path is resolved against the image’s /app working directory, so the following example places the frontend app’s build output in /app/static:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

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

Creates a new distributed application builder

createBuilder
();
const
const api: RustAppResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addRustApp(name: string, appDirectory: string): RustAppResource

Adds a Rust application to the application model.

addRustApp
('api', '../api');
await
const api: RustAppResource
api
.
ExecutableResource.withHttpEndpoint(options?: {
port?: number;
targetPort?: number;
name?: string;
env?: string;
isProxied?: boolean;
} | undefined): RustAppResource (+1 overload)

Adds an HTTP endpoint

withHttpEndpoint
({
env?: string | undefined
env
: 'PORT' });
await
const api: RustAppResource
api
.
ExecutableResource.withExternalHttpEndpoints(): RustAppResource

Marks existing http or https endpoints on a resource as external.

withExternalHttpEndpoints
();
const
const frontend: ViteAppResource
frontend
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addViteApp(name: string, appDirectory: string, options?: {
runScriptName?: string;
}): ViteAppResource (+1 overload)

Adds a Vite app to the distributed application builder.

addViteApp
('frontend', '../frontend');
await
const frontend: ViteAppResource
frontend
.
ExecutableResource.withReference(source: IResource | EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ViteAppResource (+1 overload)

Adds a reference to another resource

withReference
(
const api: RustAppResource
api
);
await
const frontend: ViteAppResource
frontend
.
ExecutableResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): ViteAppResource

Waits for another resource to be ready

waitFor
(
const api: RustAppResource
api
);
await
const api: RustAppResource
api
.
IContainerFilesDestinationResource.publishWithContainerFiles(source: IResourceWithContainerFiles, destinationPath: string): RustAppResource

Configures the resource to copy container files from the specified source resource during publishing.

publishWithContainerFiles
(
const frontend: ViteAppResource
frontend
, './static');
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

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

Runs the distributed application

run
();

Aspire builds the source resource before it builds the Rust app’s image. Copying the files doesn’t make the app serve them, so serve them from the app — for example, with the ServeDir service of the tower-http crate, pointed at the static directory. Aspire adds the files only to the Dockerfile that it generates, so an authored Dockerfile in the app directory doesn’t receive them.

For the environment variables that a Rust app receives — and how other apps discover a Rust app’s endpoints — see Connect to Rust apps.

The Rust hosting integration doesn’t add health checks to Rust resources. When your app exposes a health endpoint, add a check with WithHttpHealthCheck, as shown in Add a Rust app. Without a health check, Aspire considers a Rust app ready as soon as its cargo run process starts — before Cargo finishes building the app and the app starts listening — so resources that wait for it can start too early.

For Aspire 13.6 and later, Aspire.Hosting.Rust replaces 📦 CommunityToolkit.Aspire.Hosting.Rust for Cargo apps. To migrate an AppHost:

  1. Remove CommunityToolkit.Aspire.Hosting.Rust from the AppHost’s package references, #:package directives, or aspire.config.json, unless you use Bacon, as described in Toolkit-only Bacon support.
  2. Add Aspire.Hosting.Rust, as described in Installation.
  3. Update your AppHost code with the replacements in the following table. The table uses C# names; TypeScript AppHosts use the same names in camel case.
  4. Review how your Rust apps are published. The Community Toolkit integration requires a Dockerfile in the app directory. The first-party integration uses that Dockerfile when it exists, and generates one otherwise.
Community Toolkit APIFirst-party replacement
The workingDirectory parameter of AddRustAppThe appDirectory parameter.
Cargo options in the args parameter of AddRustAppWithCargoFeatures, WithCargoBinTarget, WithCargoReleaseBuild, and the other WithCargo* methods, or WithCargoArgs for options that don’t have a method.
Program arguments after -- in the args parameterWithArgs, without the -- separator, which Aspire adds.
RustAppExecutableResourceRustAppResource.
AddBaconAppNo first-party replacement. See Toolkit-only Bacon support.

AddBaconApp runs an app with Bacon, a background code checker for Rust that rebuilds and reruns the app when its source changes. It remains a Community Toolkit API, and the first-party integration has no replacement for it. To keep using it, keep CommunityToolkit.Aspire.Hosting.Rust alongside Aspire.Hosting.Rust, and install Bacon. In that AppHost, add Cargo apps with the first-party form of AddRustApp — a name and an appDirectory, with Cargo options set through the WithCargo* methods — rather than with the Toolkit’s workingDirectory and args parameters. Bacon apps keep the Toolkit’s behavior, including its requirement for an authored Dockerfile when you publish.