Packaging & Distribution
Ship Rust desktop apps with installers, code signing, and safe auto-update channels.
Recipe
# Tauri
cd src-tauri && cargo tauri build
# Plain Rust + cargo-bundle
cargo install cargo-bundle
cargo bundle --releaseWhen to reach for this:
- First public release to non-developers
- Enabling in-app updates without manual downloads
- macOS notarization to pass Gatekeeper
- Microsoft Store or Linux flatpak distribution
Working Example
Tauri updater config sketch (tauri.conf.json fragment):
{
"plugins": {
"updater": {
"endpoints": ["https://releases.example.com/{{target}}/{{current_version}}"],
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6I..."
}
}
}What this demonstrates:
- HTTPS endpoint template per target triple
- Embedded public key verifies update artifacts before apply
- Version gating prevents downgrades if configured
Deep Dive
How It Works
- Build produces release binary + assets.
- Bundle wraps in
.dmg,.msi,.deb, or.AppImage. - Sign attaches publisher identity (Apple, Authenticode).
- Updater downloads signed bundle diff or full package.
Platform Notes
| OS | Artifact | Signing |
|---|---|---|
| macOS | .dmg / .app | Developer ID + notarize |
| Windows | .msi / NSIS | Authenticode cert |
| Linux | deb/AppImage/flatpak | GPG for repo metadata |
Gotchas
- Unsigned macOS build - users get scary dialogs. Fix: notarize in CI with Apple credentials.
- Hard-coded dev paths in bundle - crash on user machines. Fix: runtime path resolution only.
- Updater without HTTPS - MITM installs malware. Fix: TLS + signature verify mandatory.
- Missing universal macOS build - Rosetta friction on Apple Silicon. Fix:
aarch64-apple-darwin+x86_64-apple-darwinlipo or separate artifacts. - Debug symbols in release - huge downloads. Fix: split debuginfo or strip for release lane.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Homebrew cask | Dev tool CLI/GUI | Non-technical consumer users |
| Microsoft Store | Enterprise deployment | Need custom updater day one |
| Portable zip | Internal tools | Consumer double-click install expected |
| Docker | Server apps | Desktop GUI with GPU |
FAQs
Tauri vs cargo-bundle?
Tauri includes updater, signing hooks, and WebView assets; cargo-bundle is minimal wrapper for pure Rust GUIs.
Where to store signing secrets?
CI secrets (GitHub Actions) with hardware token or cloud HSM - never in repo.
Linux packaging choice?
AppImage for universal; flatpak for sandboxed store; deb for apt-based enterprise.
Versioning scheme?
Semver; breaking database migrations bump minor/major and document in release notes.
Crash reporting?
Sentry or similar in Rust layer; symbolicate with uploaded debug symbols from release build.
Beta channel?
Separate updater endpoint or beta flag in JSON manifest listing compatible versions.
CI matrix?
Build macOS on macOS runners, Windows on windows-latest, Linux on ubuntu - cross-compile only when tested.
Icon sizes?
Provide icns/ico/png set per platform guidelines - Tauri icon generator helps.
Legal notices?
Ship LICENSE and third-party notices file for webview and Rust crate obligations.
Related
- Tauri - primary bundler path
- Native Integration - install paths
- GUI Best Practices - release checklist
- GUI Basics - build example
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.