Publish a Tauri app for Windows
This guide adds Windows (windows-x86_64) to a Tauri 2 app that publishes to Mocco. Set up the app, the updater key, tauri.conf.json and the CI key first, as in Publish a Tauri app; everything there applies to Windows too.
Pick a bundle
Tauri builds two kinds of Windows installer. Use NSIS unless you need MSI:
| Bundle | tauri build --bundles | Files in src-tauri/target/release/bundle/ |
|---|---|---|
NSIS (.exe) | nsis | nsis/App_0.2.0_x64-setup.exe and nsis/App_0.2.0_x64-setup.exe.sig |
MSI (.msi) | msi | msi/App_0.2.0_x64_en-US.msi and msi/App_0.2.0_x64_en-US.msi.sig |
NSIS installs per user without asking for an administrator, and its installer updates in place. MSI suits machines managed by group policy. With createUpdaterArtifacts: true, Tauri signs the installer itself for the updater, so the same file is both what people download and what the app installs. (With "v1Compatible", the update bundle is a separate .nsis.zip or .msi.zip with its own .sig; upload that as the update bundle instead.)
A release has one installer and one update bundle per platform, so publish NSIS or MSI, not both. Installed apps update with the kind of installer they were installed with: if you switch from MSI to NSIS, existing MSI installs get the NSIS installer.
Sign the installer first
Authenticode signing is yours, and it happens before the upload. Without it, Windows SmartScreen warns people who download the installer. Configure it in tauri.conf.json (bundle.windows.certificateThumbprint, or bundle.windows.signCommand for a cloud signing service), so Tauri signs the .exe or .msi during the build and then writes the updater .sig over the signed file.
If you sign the file after the build instead, its bytes change and the .sig no longer matches: sign it again for the updater (tauri signer sign) before the upload, or Mocco marks the release Failed with The signature doesn't match the file.
Mocco never holds your certificate or your updater private key.
The release step
On a Windows runner, after the build:
- name: Publish to Mocco
uses: fi-workers/mocco/actions/desktop-publish@<commit sha>
with:
app-id: <app id>
version: ${{ steps.version.outputs.version }}
notes-file: RELEASE_NOTES.md
artifacts: |
windows-x86_64 installer src-tauri/target/release/bundle/nsis/App_${{ steps.version.outputs.version }}_x64-setup.exe
windows-x86_64 updater src-tauri/target/release/bundle/nsis/App_${{ steps.version.outputs.version }}_x64-setup.exe
channel: stable
env:
MOCCO_API_KEY: ${{ secrets.MOCCO_API_KEY }}The same file is listed twice, once per kind; the .sig next to it is read for the updater line. For MSI, use the two msi/…_x64_en-US.msi lines instead.
Mocco serves the update under windows-x86_64 and under the key newer updater plugins look up first: windows-x86_64-nsis, or windows-x86_64-msi when the update bundle's name ends in .msi or .msi.zip. Nothing changes in tauri.conf.json: the endpoint's {{target}}/{{arch}} is already windows/x86_64.
Build every platform, publish one release
Build each platform on its own runner, then publish all the files as one release from a single job, so the version appears everywhere at once and a failed build publishes nothing.
name: Release
on:
push:
tags: ['v*']
jobs:
build:
strategy:
matrix:
include:
- runner: macos-latest
platform: darwin-aarch64
bundles: app,dmg
- runner: windows-latest
platform: windows-x86_64
bundles: nsis
- runner: ubuntu-22.04
platform: linux-x86_64
bundles: appimage
runs-on: ${{ matrix.runner }}
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
steps:
- uses: actions/checkout@<commit sha>
# Install Node, Rust and (on Linux) the system packages Tauri needs here.
- run: npm ci
- run: npm run tauri build -- --bundles ${{ matrix.bundles }}
- uses: actions/upload-artifact@<commit sha>
with:
name: ${{ matrix.platform }}
path: |
src-tauri/target/release/bundle/dmg/*.dmg
src-tauri/target/release/bundle/macos/*.app.tar.gz*
src-tauri/target/release/bundle/nsis/*-setup.exe*
src-tauri/target/release/bundle/appimage/*.AppImage*
publish:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@<commit sha>
with:
path: release
- id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Publish to Mocco
uses: fi-workers/mocco/actions/desktop-publish@<commit sha>
with:
app-id: <app id>
version: ${{ steps.version.outputs.version }}
artifacts: |
darwin-aarch64 installer release/darwin-aarch64/dmg/App_${{ steps.version.outputs.version }}_aarch64.dmg
darwin-aarch64 updater release/darwin-aarch64/macos/App.app.tar.gz
windows-x86_64 installer release/windows-x86_64/App_${{ steps.version.outputs.version }}_x64-setup.exe
windows-x86_64 updater release/windows-x86_64/App_${{ steps.version.outputs.version }}_x64-setup.exe
linux-x86_64 installer release/linux-x86_64/App_${{ steps.version.outputs.version }}_amd64.AppImage
linux-x86_64 updater release/linux-x86_64/App_${{ steps.version.outputs.version }}_amd64.AppImage
channel: stable
env:
MOCCO_API_KEY: ${{ secrets.MOCCO_API_KEY }}upload-artifact keeps the folders below the paths' common root, so check the downloaded layout once (ls -R release) and adjust the paths. Pin every action to a commit. The publish job needs no Rust, no signing key and no Windows runner: it only reads the files and their .sig.
Next
Publish a Tauri app for Linux: AppImage, deb and rpm.
Publish with curl: the same upload from any CI. Use the content type
application/vnd.microsoft.portable-executablefor an.exeandapplication/x-msifor an.msi.