-
Notifications
You must be signed in to change notification settings - Fork 0
Deployment Single Binary
Cadenza's promise: whoever you hand the binary to runs your program. No .NET runtime to pre-install, no dotnet command, no extra files.
This guide applies to all five SDK variants (Cadenza, Cadenza.Worker, Cadenza.Web, Cadenza.Mcp, Cadenza.Agent). The defaults are the same: a single self-contained binary, ReadyToRun-compiled, with single-file compression enabled.
dotnet publish app.cs -r linux-x64 -c ReleaseOutput: bin/Release/net10.0/linux-x64/publish/app — roughly 30–40 MB after compression.
That's the whole flow. The defaults that ship with Cadenza set SelfContained=true, PublishSingleFile=true, PublishReadyToRun=true, and EnableCompressionInSingleFile=true — there are no extra /p: flags to pass.
| Platform | RID |
|---|---|
| Linux x64 | linux-x64 |
| Linux ARM64 | linux-arm64 |
| Linux musl x64 (Alpine) | linux-musl-x64 |
| Linux musl ARM64 | linux-musl-arm64 |
| macOS x64 | osx-x64 |
| macOS Apple Silicon | osx-arm64 |
| Windows x64 | win-x64 |
| Windows ARM64 | win-arm64 |
Cross-compile freely — no platform toolchain needed on the build host.
Disable compression — the binary is ~50–70 MB instead of ~30–40 MB, but startup skips decompression:
dotnet publish app.cs -r linux-x64 -c Release \
-p:EnableCompressionInSingleFile=falseBy default, the single-file host extracts a small number of native libraries to a temp directory on first launch. Bundle them into the binary instead:
dotnet publish app.cs -r linux-x64 -c Release \
-p:IncludeNativeLibrariesForSelfExtract=trueUseful in containers and read-only filesystems.
NativeAOT compiles to native code ahead of time. Binaries shrink to ~10–30 MB and cold start drops to milliseconds.
Add one directive to the script:
#:property PublishAot=trueThen publish normally:
dotnet publish app.cs -r linux-x64 -c ReleaseFor even smaller AOT binaries, also drop ICU:
#:property PublishAot=true
#:property InvariantGlobalization=true| SDK | AOT-clean? |
|---|---|
| Cadenza | ✅ |
| Cadenza.Worker | ✅ |
| Cadenza.Web | ✅ |
| Cadenza.Mcp | ✅ |
| Cadenza.Agent | Microsoft.Extensions.AI is not AOT-safe today |
For AOT-required AI workloads, compose Cadenza.Web + a manual IChatClient rather than Cadenza.Agent.
AOT requires every type that crosses a reflection boundary to be visible at compile time:
-
JSON: use source-generated
JsonSerializerContext(theHttp.GetJson/Json.Parsesignatures already require it). -
Minimal API handlers: keep your handler signatures explicit; avoid
dynamicandobjectrequest bodies. - Reflection-heavy libraries: may or may not work. Check the library's docs.
| Concern | JIT (default) | AOT |
|---|---|---|
| Binary size | 30–40 MB | 10–30 MB |
| Cold start | ~100–300 ms | ~10–30 ms |
| Build time | Fast | Slower (1–2 min) |
| All libraries work | Yes | Most, not all |
| Reflection-heavy code | Fine | Needs care |
Default to JIT. Reach for AOT when you ship widely (CLIs, daemons in many containers) or when start latency matters (FaaS, short-lived workers).
AOT implies trimming. For trimmed-but-not-AOT builds:
#:property PublishTrimmed=true
#:property TrimMode=fullTrimming removes unused IL from the binary. Most pure-.NET code trims cleanly; libraries that use reflection need either [DynamicallyAccessedMembers] annotations or trim-warning suppression.
for rid in linux-x64 linux-arm64 osx-arm64 win-x64; do
dotnet publish app.cs -r $rid -c Release -o "./out/$rid"
doneYou get four binaries, one per platform, from the same source.
bin/Release/net10.0/<RID>/publish/<name>[.exe]
with <name> taken from the .cs filename. Copy it anywhere and run.
- Spec, §3.4 — formal deployment model
- Troubleshooting — common publish-time errors
- Microsoft Learn: Single-file deployment · NativeAOT
- Deployment Container — when you want it in an OCI image without writing a Dockerfile
-
Directives —
#:propertyreference - Troubleshooting
Cadenza · MIT · .NET 10+ · github.com/rkttu/cadenza · No orchestra. No project. Just one file, playing solo.