Desktop app (Tauri)
A Tauri 2 desktop app that is your web app in a native window — the same typed hooks, the platform adapter from @voltro/desktop/tauri (keychain token store, updater against your release feed, deep links, tray/menu commands). Tauri owns cargo and the window; voltro dev runs the sibling web app + api.
A Tauri 2 desktop app that puts your existing web app in a native window — nothing in the web app changes; what differs is the platform adapter installed before it mounts. Template id: desktop-app (kind: desktop).
Tauri owns the dev loop, not
voltro dev. The window is started withpnpm tauri devand loads the web dev server; production bundles the web app'sdist. That is why adesktopapp gets no port and is not part ofvoltro dev's orchestration — and why it needs the Rust toolchain on the machine that builds it.
Boots on macOS, Windows and Linux. The framework's desktop proof workflow scaffolds this template, compiles the Tauri shell on all three runners and starts it: the window's boot report (
awaitWindowBoot→window_booted) says the Tauri adapter was installed before the web app mounted, on every OS (green on 2026-09-26). Signing, notarization and your own updater key remain your steps.
Scaffold
# A project with a backend, a web app and a desktop app:
voltro create-project acme --api=api-backend --web=frontend-app --desktop
# …or add one to an existing project later:
voltro add-app desktop --template=desktop-app --to acmeWhat ships
desktop-app/
voltro.desktop.ts # web app, shell, features, updates channel, identifier
src/
main.ts # the window's platform script: installs the adapter, reports the boot
platform.ts # createTauriPlatform from the Tauri plugins in package.json
lib/commands.ts # PURE: the JS side of the Rust command pairs (keychain, tray, menu) — tested
src-tauri/
Cargo.toml, tauri.conf.json, build.rs
src/lib.rs # plugin registration + keyring / set_tray / set_menu commands
capabilities/default.json # the core; voltro.generated.json is derived from voltro.desktop.ts
icons/icon.png # `pnpm tauri icon` derives the platform sets
tests/commands.test.tsThe commands
| Command | Does |
|---|---|
voltro desktop capabilities |
src-tauri/capabilities/voltro.generated.json from features — an app that declares no shell gets no shell permission |
voltro desktop platform |
src/main.ts → src-tauri/gen/platform.js, the window's platform script the shell injects before the web app's own scripts (also the beforeDevCommand) |
voltro desktop build |
the sibling web build → the capabilities → the platform script → tauri build → dist-desktop/manifest.json (every bundle with kind, target, sha256) |
voltro desktop ci |
.github/workflows/desktop-release.yml: macOS (arm64 + x64), Windows, Linux; signing and notarization from repository secrets; artefacts published with voltro release |
voltro desktop publish |
upload a manifest's artefacts into a release on the api's release feed |
tauri.conf.json's plugins.updater.endpoints points at that feed
(/releases/<app>/tauri/<channel>/{{target}}-{{arch}}/{{current_version}}), so the
rollout, rollback and minimum-version policy are the same ones your other apps
follow. voltro desktop build refuses a placeholder updater public key and an
empty endpoint list rather than shipping an updater that cannot verify anything.
Signing
Nothing secret lives in the template. pnpm tauri signer generate mints the
updater key pair (public key → tauri.conf.json, private key → a CI secret);
Developer ID + notarization and Windows Authenticode are the secrets the
generated workflow names in its header.