Goal
Why this matters
Prerequisites
dotnet build: compiles assemblies, typically run for local development.dotnet publish: creates a self-contained folder/app ready to run on target machines (Optionally includes .NET runtime).Release configuration: dotnet publish -c Release.Avalonia ships MSBuild targets that compile XAML and pack resources alongside your assemblies. Understanding them keeps design-time and publish-time behavior in sync.
CompileAvaloniaXamlTask runs during BeforeCompile to turn .axaml into generated .g.cs. If a publish build reports missing generated files, confirm the Avalonia NuGet packages are referenced and the project imports Avalonia.props/targets.AvaloniaResource items embed static content. Include them explicitly so publish outputs contain everything:<ItemGroup>
<AvaloniaResource Include="Assets/**" />
<AvaloniaResource Include="Themes/**/*.axaml" />
</ItemGroup>
build/BuildTargets.targets tweak platform packaging. Review them before overriding publish stages.<AvaloniaUseCompiledBindings>true</AvaloniaUseCompiledBindings> consistently across Debug/Release so the previewer and publish builds agree.Target Name="AfterPublish" or a Directory.Build.targets file; Avalonia emits its files before your target runs, so you can safely zip or notarize afterward.Common RIDs:
win-x64, win-arm64.osx-x64 (Intel), osx-arm64 (Apple Silicon), osx.12-arm64 (specific OS version), etc.linux-x64, linux-arm64 (distribution-neutral), or distro-specific RIDs (linux-musl-x64).android-arm64, android-x86, etc. (handled in platform head).ios-arm64, iossimulator-x64.browser-wasm (handled by browser head).dotnet publish -c Release -r win-x64 --self-contained false
Smaller download; target machine must have matching .NET runtime. Good for enterprise scenarios.
dotnet publish -c Release -r osx-arm64 --self-contained true
Larger download; runs on machines without .NET. Standard for consumer apps.
dotnet publish -c Release -r linux-x64 /p:SelfContained=true /p:PublishSingleFile=true
Creates one executable (plus a few native libraries depending on platform). Avalonia may extract resources native libs to temp; test startup.
dotnet publish -c Release -r win-x64 /p:SelfContained=true /p:PublishReadyToRun=true
Precompiles IL to native code; faster cold start at cost of larger size. Measure before deciding.
dotnet publish -c Release -r osx-arm64 /p:SelfContained=true /p:PublishTrimmed=true
Aggressive size reduction; risky because Avalonia/XAML relies on reflection. Requires careful annotation/preservation with DynamicDependency or ILLinkTrim files. Start without trimming; enable later with thorough testing.
| Option | Pros | Cons |
|---|---|---|
| Framework-dependent | Small | Requires runtime install |
| Self-contained | Runs anywhere | Larger downloads |
| Single-file | Simple distribution | Extracts natives; more memory |
| ReadyToRun | Faster cold start | Larger size |
| Trimmed | Smaller | Risk of missing types |
Publish outputs to bin/Release/<TFramework>/<RID>/publish.
Examples:
bin/Release/net8.0/win-x64/publishbin/Release/net8.0/linux-x64/publishbin/Release/net8.0/osx-arm64/publishVerify resources (images, fonts) present; confirm AvaloniaResource includes them. Use dotnet publish /bl:publish.binlog and inspect the binlog with MSBuild Structured Log to confirm each resource path is copied.
appsettings.json, MyApp.runtimeconfig.json, and .deps.json to ensure trimming or single-file options didn't remove dependencies.MyApp.app/Contents/Info.plist, MyApp.msix) before shipping.AvaloniaResource Include="Assets/Icons/**/*". The build task preserves folder structure when copying to publish output.<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> alongside AvaloniaResource. That avoids bloating assemblies and keeps startup fast.<AvaloniaResource Update="Assets/logo.svg" LogicalPath="resm:MyApp.Assets.logo.svg">. Logical paths become the keys your app uses with AssetLoader.Target Name="VerifyAvaloniaResources" AfterTargets="ResolveAvaloniaResource" to ensure required files exist; failing early prevents subtle runtime crashes after publish.dotnet publish /p:WindowsPackageType=msix or MSIX packaging tool. Enables automatic updates, store distribution..app bundle with Avalonia.DesktopRuntime.MacOS packaging scripts.codesign, xcrun altool/notarytool.Avalonia.AppTemplate.AppImage or AppImage tooling to bundle.org.freedesktop.Platform runtime.snapcraft.yaml to bundle.MyApp.Android) builds APK/AAB using Android tooling../gradlew bundleRelease or dotnet publish using .NET Android tooling).MyApp.iOS) builds .ipa using Xcode or dotnet publish -f net8.0-ios -c Release with workload.dotnet publish -c Release in browser head (MyApp.Browser). Output in bin/Release/net8.0/browser-wasm/AppBundle.dotnet publish per target.jobs:
publish:
runs-on: $
strategy:
matrix:
include:
- os: windows-latest
rid: win-x64
- os: macos-latest
rid: osx-arm64
- os: ubuntu-latest
rid: linux-x64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore workloads
run: dotnet workload restore
- name: Publish
run: |
dotnet publish src/MyApp/MyApp.csproj \
-c Release \
-r $ \
--self-contained true \
/p:PublishSingleFile=true \
/p:InformationalVersion=$
- name: Collect binlog on failure
if: failure()
run: dotnet publish src/MyApp/MyApp.csproj -c Release -r $ /bl:publish-$.binlog
- uses: actions/upload-artifact@v4
with:
name: myapp-$
path: src/MyApp/bin/Release/net8.0/$/publish
- name: Upload binlog
if: failure()
uses: actions/upload-artifact@v4
with:
name: publish-logs-$
path: publish-$.binlog
azure-pipelines.yml to reuse matrix publishing, signing, and artifact staging.Target Name="SignArtifacts" AfterTargets="Publish" or AfterTargets="BundleApp" in Directory.Build.targets so both local builds and CI run the same packaging hooks.dotnet publish with --self-contained false/true to compare sizes and startup times; pick best trade-off.| Problem | Fix |
|---|---|
| Missing native libs on Linux | Install required packages (libicu, fontconfig, libx11, etc.). Document dependencies. |
| Startup crash only in Release | Enable logging to file; check for missing assets; ensure AvaloniaResource includes. |
| High CPU at startup | Investigate ReadyToRun vs normal build; pre-load data asynchronously vs synchronously. |
| Code signing errors (macOS/Windows) | Confirm certificates, entitlements, notarization steps. |
| Publisher mismatch (store upload) | Align package IDs, manifest metadata with store requirements. |
CompileAvaloniaXamlTask failure |
Clean obj/, fix XAML build errors, and examine the /bl binlog to inspect generated task arguments. |
| Native dependency failure (Skia/WASM) | Use ldd/otool/wasm-ld reports to list missing libraries; bundle them or switch to self-contained publishes. |
win-x64, osx-arm64, linux-x64. Run each and note size/performance differences.PublishSingleFile and PublishReadyToRun for one target; compare startup time and size.DynamicDependency or ILLinkTrim descriptors and verify at runtime.docs/build.mdCompileAvaloniaXamlTask.csAvaloniaResource.csbuild/BuildTargets.targetssamples/ControlCatalogazure-pipelines.yml.axaml files and resources reach your publish output?What's next