Publishing Best Practices

A complete guide to preparing, versioning, and distributing your Tauri v2 desktop application for production release.

Releasing a desktop application involves more than just running tauri build. You need to verify security configurations, manage version numbers correctly, sign the binaries, choose the right installer format, and ensure your users can install and update the app without friction. A well-defined release process catches problems before they reach your users and makes subsequent releases predictable. Work through the Release Checklist first.

This guide covers three interconnected areas: a pre‑release checklist that walks through each step from hardening to distribution, a version management strategy that works with Tauri's auto‑updater, and platform‑specific distribution best practices. Each section builds on the previous one, so if you are preparing your first release, start at the beginning and work through the entire document.

Prerequisites:

This guide assumes you have a working Tauri v2 project with React and Vite as the frontend. If you haven't built the app yet, review Build Configuration and Packaging Applications earlier in this chapter first.

Release Checklist

A production release is not a single command. It is a sequence of deliberate checks that verify every layer of the application—from the security model down to the final installer. Running through these steps in order catches mistakes that are expensive to fix after users have already downloaded the software.

1

Step 1: Harden the Security Configuration

Before compiling anything, lock down what your frontend can access. Tauri v2 uses a capability‑based permission system, not a blanket allow‑list. Each window gets only the permissions it genuinely needs. Review Permission Best Practices if you are unsure what to grant.

Open the src-tauri/capabilities/ directory and review every file. A minimal capability for a main window that only needs the default APIs and file system access to the app data directory looks like this:

src-tauri/capabilities/main-capability.json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "main-capability",
  "description": "Core capability for the main window",
  "windows": ["main"],
  "permissions": [
    "core:default",
    {
      "identifier": "fs:scope-app-recursive",
      "allow": [{ "path": "$APPDATA/*" }]
    }
  ]
}

Confirm that every capability file is referenced in the main configuration:

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "capabilities": ["main-capability"]
    }
  }
}

Next, set a strict Content Security Policy. A CSP limits which scripts, styles, and connections the WebView can load. Even if an XSS vulnerability exists, a tight CSP prevents the attacker from exfiltrating data or injecting foreign code.

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' ipc: http://ipc.localhost"
    }
  }
}

Avoid wildcard permissions:

Wildcard permissions like "core:allow-all" or "*" grant every command to every window. They defeat the purpose of capability scoping. Start with the defaults and add permissions one at a time as you develop features.

If your application loads any resource from a remote URL—for instance, an OAuth flow or embedded documentation—you must explicitly allow it in a remote capability file. Without this, the Tauri API will be unavailable to that remote content.

src-tauri/capabilities/remote.json
{
  "$schema": "../gen/schemas/remote-schema.json",
  "identifier": "remote-capability",
  "description": "Allow remote development sources",
  "windows": ["main"],
  "remote": {
    "urls": ["https://*.myapp.com"]
  },
  "permissions": ["core:default"]
}
2

Step 2: Update the Version and Write a Changelog

The version number is the contract between your release and the auto‑updater. Tauri v2 looks for the version field in tauri.conf.json first. If that field is absent, it falls back to the version in src-tauri/Cargo.toml. Set it explicitly to avoid surprises.

src-tauri/tauri.conf.json
{
  "version": "1.2.0"
}

Keep a CHANGELOG.md in the repository root. Each release entry should describe what changed, what was fixed, and any breaking modifications. The auto‑updater itself does not read the changelog, but users and maintainers rely on it.

Version mismatch breaks auto‑updates:

The updater plugin compares the current version against a remote endpoint that returns version metadata. If the version you publish does not follow strict semantic versioning (MAJOR.MINOR.PATCH), the comparison logic may skip or reject updates. Never use pre‑release suffixes in the version field unless you have configured the updater to accept them.

3

Step 3: Build the Production Binary

A production build strips debug symbols, enables link‑time optimisation, and removes unused code. Tauri relies on Cargo profiles for the Rust side and your frontend bundler (Vite) for the web assets.

Set the release profile in src-tauri/Cargo.toml:

src-tauri/Cargo.toml
[profile.release]
codegen-units = 1
lto = "fat"
opt-level = "z"
panic = "abort"
strip = true

The frontend already benefits from Vite's production optimisations. Run the build command that compiles everything and creates the platform‑specific bundles.

npm run tauri build

This single command builds the Rust backend, bundles the Vite‑generated frontend, and produces the default installers for your host platform. The output appears in src-tauri/target/release/bundle/.

Remove unused commands:

In tauri.conf.json, set build.removeUnusedCommands to true. This prevents dead command handlers from being compiled into the binary, reducing both size and attack surface.

4

Step 4: Sign the Application

Code signing attaches a digital signature that proves you are the author and that the binary has not been tampered with. Windows and macOS gatekeepers enforce signing; without it, users see scary security warnings or cannot launch the app at all. Linux packaging systems prefer GPG signatures on repositories, though standalone binaries are not mandated to be signed.

The process differs per platform. For a detailed walkthrough, refer to the code signing section earlier in this chapter. At a minimum, ensure that:

  • macOS: Every .app bundle, DMG, and pkg is signed with a Developer ID certificate and notarised using notarytool.
  • Windows: The installer (MSI/NSIS) and the executable inside it are signed with a code signing certificate from a trusted certificate authority.
  • Linux: If you distribute through a repository or Flathub, the package manifest is GPG‑signed. Standalone AppImages do not require signing, but it is a good practice to publish a checksum file signed with your GPG key.

Check that signing worked:

On macOS, run codesign -dvvv /path/to/YourApp.app. On Windows, right‑click the installer → Properties → Digital Signatures. If the signature shows as valid, the build step is complete.

5

Step 5: Package for Distribution

The default tauri build creates the installer formats configured in tauri.conf.json under bundle > targets. Before releasing, verify that the right set of formats is enabled for each target platform.

If you need to create only a specific bundle—for example, a DMG for macOS outside the App Store—split the build and bundle steps:

npm run tauri build -- --no-bundle
npm run tauri bundle -- --bundles dmg

This is useful when you must sign the .app bundle manually before wrapping it in a DMG, or when you need to pass a different configuration file for App Store submission.

npm run tauri bundle -- --bundles app --config src-tauri/tauri.appstore.conf.json

Test every installer on a clean machine or virtual environment before publishing. A corrupted MSI or a DMG that fails to mount erodes trust instantly.

6

Step 6: Verify and Distribute

After the installers are signed and tested, upload them to your distribution channels: a website, GitHub Releases, the Microsoft Store, the Mac App Store, Snapcraft, Flathub, or a cloud service like CrabNebula that also handles auto‑updates.

Before announcing the release, download the installer from the public URL and install it on a real device. This catches CDN misconfigurations, missing runtime dependencies, and permission prompts you might have overlooked during development.

Version Management

Every release needs a version number, but in Tauri that number is not just cosmetic. It drives the auto‑updater, appears in package metadata, and is visible in system dialogs. Getting versioning right from the start prevents update failures and confused users. See Version Management. See Version Management.

Where the Version Is Defined

Tauri v2 checks tauri.conf.json first. If a top‑level version key is present, that value is used everywhere: in the compiled binary, the installers, and the update manifest. If the key is absent, Tauri falls back to the version field in src-tauri/Cargo.toml.

The recommended approach is to set the version in tauri.conf.json and keep the Cargo version in sync manually or through your release automation. That way, the single source of truth lives in the Tauri configuration, where it is most visible.

src-tauri/tauri.conf.json
{
  "$schema": "https://raw.githubusercontent.com/nickknapton12/tauri-v2-schema/main/schema.json",
  "productName": "MyApp",
  "version": "1.2.0",
  "identifier": "com.mycompany.myapp",
  "build": {
    "frontendDist": "../dist",
    "devUrl": "http://localhost:1420"
  }
}

Do not rely solely on Cargo.toml:

If both tauri.conf.json and Cargo.toml carry a version field but they differ, Tauri uses the tauri.conf.json value. The mismatch does not cause a build error, but it will confuse anyone reading the two files. Automate the synchronisation step in your CI pipeline to keep them identical.

Semantic Versioning and the Updater

The Tauri updater plugin expects versions that follow semantic versioning: MAJOR.MINOR.PATCH. It compares the user’s current version with the version returned by the update server. If the server reports a higher version, the updater downloads and installs it.

Stick to a predictable versioning scheme:

  • MAJOR – Increment when you introduce breaking changes that require users to take action (e.g., a new minimum OS requirement).
  • MINOR – Increment when you add backwards‑compatible features.
  • PATCH – Increment for bug fixes and small improvements.

Pre‑release tags like 1.2.0-beta.1 are not automatically recognised by the updater. If you want to distribute beta releases through the same channel, configure the updater’s endpoints to accept pre‑release identifiers. Otherwise, stick to plain numeric versions for public releases.

Changelog Discipline

A changelog is not just a list of commits. It is a document aimed at end users who want to know whether they should update now or wait. Write a brief, clear entry for each release that highlights:

  • New features and how to find them.
  • Bug fixes that affect common workflows.
  • Any action the user must take (e.g., “This release drops support for Windows 7”).

Keep the changelog in a CHANGELOG.md file at the repository root. Automation tools can help format entries, but a human should always write the final summary.

Distribution Best Practices

Once the application is built, signed, and versioned, you need to get it into users’ hands in a way that feels native to each platform. The right installer format, code signing workflow, and update mechanism differ significantly between Windows, macOS, and Linux. The Distribution Best Practices page collects those platform notes. Platform-specific notes are on Distribution Best Practices.

Windows users expect an installer, not a raw .exe. Tauri v2 can produce both NSIS and MSI (via WiX) installers. MSI is preferred for enterprise environments because it supports group policy deployment and silent installation. NSIS installers are lighter and simpler to configure for small projects.

In tauri.conf.json, under bundle > windows, enable the desired format:

src-tauri/tauri.conf.json
{
  "bundle": {
    "active": true,
    "targets": "all",
    "windows": {
      "wix": {
        "language": "en-US"
      },
      "nsis": {
        "installMode": "currentUser"
      }
    }
  }
}

Code signing is mandatory if you want to avoid SmartScreen warnings. Purchase an Extended Validation (EV) or standard code signing certificate from a Certificate Authority like DigiCert or Sectigo. Store the certificate securely and use it in your CI environment with a hardware token or a cloud‑based signing service.

Distribute the signed installer through a download page, a GitHub release, or the Microsoft Store. The Microsoft Store requires packaging the app as an MSIX, which Tauri supports through the msix bundle target.

Unsigned installers trigger SmartScreen:

Windows Defender SmartScreen will block an unsigned installer with a full‑screen warning. Some users will abandon the installation immediately. Always sign before publishing.

Automate Releases with CI/CD

Manual releases do not scale. A continuous integration pipeline ensures that every tag produces identical, signed artifacts without human variation. A typical GitHub Actions workflow does the following:

  • Checks out the code at the release tag.
  • Installs the Tauri CLI and system dependencies.
  • Runs npm run tauri build with the required signing secrets.
  • Uploads the signed installers as workflow artifacts or directly to GitHub Releases.

Because signing certificates and Apple credentials are secrets, store them in the repository’s secrets store and never log them. For macOS notarisation, use an app‑specific password stored in the keychain and referenced through the APPLE_PASSWORD environment variable.

Choose an Update Strategy

The Tauri updater plugin lets you ship new versions after the initial install. It pulls a JSON file from a server endpoint that contains the new version number, release notes, and download URLs for each platform. Configure the endpoint in tauri.conf.json:

src-tauri/tauri.conf.json
{
  "plugins": {
    "updater": {
      "endpoints": ["https://releases.myapp.com/update/{{target}}/{{current_version}}"]
    }
  }
}

The {{target}} placeholder expands to the platform triplet (e.g., windows-x86_64), and {{current_version}} is the version the user is running. Your server must respond with a JSON object that includes version, notes, and platforms containing the download URLs.

If maintaining your own update server is not feasible, services like CrabNebula Cloud handle hosting, update delivery, and analytics. They integrate directly with Tauri’s updater and remove the need to manage infrastructure.

Common Distribution Mistakes

Ignoring platform‑specific glibc and WebKit versions:

Building on a rolling‑release Linux distribution and shipping an AppImage that depends on a bleeding‑edge glibc version will break on older LTS systems. Always build inside a container or VM that matches your minimum supported environment.

Forgetting to update the public download URL after release:

The auto‑updater endpoint must return the exact URL of the new installer. If the URL changes after the release is published (for example, because the file was moved in cloud storage), existing installations will silently fail to update.

Consider a phased rollout:

If you have thousands of users, rolling out an update to everyone at once risks turning a small bug into a widespread incident. Use the updater’s date‑based or percentage‑based rollout features if you build your own update server, or use a cloud provider that supports gradual releases.


Every successful release is a combination of security review, precise versioning, correct packaging, and thoughtful distribution. The checklist at the beginning of this guide forces you to verify each layer before a single user downloads the app. Once that discipline is in place, version management and distribution become repeatable steps in a pipeline rather than sources of last‑minute stress.

Release Checklist

A systematic verification sequence to confirm your Tauri v2 application is ready for production distribution, covering builds, resources, external binaries, and installers

Version Management

Manage your Tauri application's version number with semantic versioning, produce clear release notes and changelogs, and automate the process for consistent releases.

Distribution Best Practices

Practical guidelines for distributing your Tauri v2 application securely and efficiently, covering installer optimization, cross-platform testing, checksums, previous release maintenance, and automated workflows