Dette indhold er ikke tilgængeligt i dit sprog endnu.
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.
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.
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.
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:
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.
Builds 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.
Builds 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:
The example that you select with WithCargoExample.
The binary that you select with WithCargoBinTarget.
The package’s default-run binary, when its Cargo.toml file sets one.
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.
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:
var builder =DistributedApplication.CreateBuilder(args);
builder.AddRustApp("api","../api")
.WithEnvironment("RUST_LOG","info")
.WithEnvironment("RUST_BACKTRACE","1");
builder.Build().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:
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.
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.
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.
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:
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:
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:
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.
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.
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.
Add Aspire.Hosting.Rust, as described in Installation.
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.
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 API
First-party replacement
The workingDirectory parameter of AddRustApp
The appDirectory parameter.
Cargo options in the args parameter of AddRustApp
WithCargoFeatures, WithCargoBinTarget, WithCargoReleaseBuild, and the other WithCargo* methods, or WithCargoArgs for options that don’t have a method.
Program arguments after -- in the args parameter
WithArgs, without the -- separator, which Aspire adds.
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.