Adding External Binaries

Configure the externalBin field in Tauri v2 to bundle platform-specific executables as sidecars

Sidecars are self-contained executables shipped with your Tauri application — CLIs, helper daemons, or language runtimes packaged with PyInstaller or similar tools. Adding one to a Tauri v2 project means telling the bundler where to find each platform’s binary and how they are named. The entire configuration lives in a single externalBin array under bundle in tauri.conf.json.

Previously covered:

If you need a conceptual overview of why sidecars exist and when to use them, read Understanding Sidecars first. This page assumes you already have a binary ready to embed.

The process breaks into four concrete steps: produce the right files for every architecture you target, place them in the expected directory, declare their location in the config file, and verify the bundler picks them up.

1

Step 1: Build a binary for each target platform

A single source binary won't work across operating systems and CPU architectures. You must compile (or pack) a separate executable for every target triple you plan to support — for example, x86_64-unknown-linux-gnu on 64-bit Linux or aarch64-apple-darwin on Apple Silicon Macs.

The Tauri bundler identifies each binary by a suffix: the base name from your config plus -$TARGET_TRIPLE before any file extension. If your config entry is "binaries/my-sidecar", then on an Intel Mac the bundler will look for binaries/my-sidecar-x86_64-apple-darwin.

To see your current machine’s triple, run:

rustc --print host-tuple

That command works on any platform where Rust is installed. Use it to suffix each compiled binary. A small Node.js helper can rename files after a build:

import { execSync } from 'child_process';
import fs from 'fs';
const extension = process.platform === 'win32' ? '.exe' : '';
const targetTriple = execSync('rustc --print host-tuple').toString().trim();
if (!targetTriple) {
  console.error('Failed to determine platform target triple');
  process.exit(1);
}
fs.renameSync(
  `src-tauri/binaries/sidecar${extension}`,
  `src-tauri/binaries/sidecar-${targetTriple}${extension}`
);

Cross‑compilation caveat:

This script renames a binary already produced for the current machine. It is not a build script — you still need a separate compilation step for each architecture you ship. Renaming a binary compiled for x86_64 to an arm64 suffix will produce a broken executable.

2

Step 2: Place binaries in the expected folder

Relative paths in externalBin are resolved from the directory that contains tauri.conf.json, i.e. src-tauri. The community convention is a binaries/ subfolder, which keeps sidecars self-contained and easy to map in the config.

Here is a typical layout after you’ve prepared binaries for three platforms:

src-tauri/
├── binaries/
│   ├── my-sidecar-x86_64-unknown-linux-gnu
│   ├── my-sidecar-x86_64-pc-windows-msvc.exe
│   ├── my-sidecar-aarch64-apple-darwin
│   └── my-sidecar-x86_64-apple-darwin
├── src/
├── Cargo.toml
└── tauri.conf.json

The binary name must match the config entry without the triple and extension. For "binaries/my-sidecar", the file in the folder is called my-sidecar-x86_64-…; the bundler appends the triple automatically when scanning.

Executable permissions:

On macOS and Linux the binary file must have the executable bit set (chmod +x). Without it the bundler may copy the file successfully, but the runtime will fail to launch the process. Always verify permissions before checking into version control.

3

Step 3: Declare the sidecar in tauri.conf.json

Open src-tauri/tauri.conf.json and add an externalBin array inside the bundle object. Each entry is the path to the binary’s location, minus the triple and the file extension.

src-tauri/tauri.conf.json
{
  "bundle": {
    "externalBin": ["binaries/my-sidecar"]
  }
}

Absolute paths are allowed but rarely necessary. Relative paths keep the project portable across developer machines and CI environments.

The entry is the logical name:

The string "binaries/my-sidecar" acts as a logical identifier. When you later spawn the sidecar from Rust or JavaScript, you will pass the same string (without triple or extension) to the shell plugin’s sidecar() method. The plugin derives the actual binary path at runtime by adding the host triple.

4

Step 4: Verify the bundler picks up the binaries

Run a debug build to confirm Tauri discovers the sidecar without errors:

npm run tauri build -- --debug

The CLI will copy the appropriate architecture’s binary into the application bundle. If the build fails with “Failed to copy external binaries”, check:

  • The file name exactly matches the pattern basename-$TARGET_TRIPLE.
  • The triple suffix corresponds to the architecture you are building for, not necessarily the host machine. Use rustc --print host-tuple on the build host if targeting the same architecture.
  • No extra characters before the hyphen that separates the name and triple.

Silent success:

A passing build without sidecar-related errors means the binary was found and embedded. You can confirm by inspecting the final app bundle: on macOS look inside Contents/MacOS/, on Linux the .deb data archive, and on Windows the installation folder.

How the bundler selects a binary

At build time the bundler computes the target triple for the platform being compiled and searches the externalBin directories for a file named entry-$TRIPLE. If you are building for x86_64-unknown-linux-gnu and the config entry is binaries/my-sidecar, the file must be:

src-tauri/binaries/my-sidecar-x86_64-unknown-linux-gnu

For a debug build targeting your own machine, this triple is exactly what rustc --print host-tuple prints. In CI you may cross-compile for a different triple, so the file name must match the build target, not the CI runner’s architecture.

Multiple entries in externalBin are supported — just repeat the naming convention for each one.

Universal macOS binaries

When you build a universal macOS app (targeting both Intel and Apple Silicon), Tauri needs to include binaries that run on both architectures. The bundler currently expects a binary named with the universal-apple-darwin suffix if you want a single file to cover both, but runtime behaviour may still select the architecture-specific name. The most reliable path is to provide separate binaries for each architecture (x86_64-apple-darwin and aarch64-apple-darwin) and let the bundler choose the right one during the build. If you must ship a single fat binary, use lipo to merge the two architecture-specific executables and name the result my-sidecar-universal-apple-darwin. This area is evolving; check the Tauri issue tracker for the latest status.

Summary

Configuring externalBin only makes the binaries available inside the bundle. You still need to launch them — that requires the tauri-plugin-shell plugin and the correct permissions in your capability file.


Quick reference

TaskKey point
Config fieldbundle.externalBin in tauri.conf.json
Naming ruleentry-$TARGET_TRIPLE (e.g., my-sidecar-x86_64-unknown-linux-gnu)
Relative path baseDirectory containing tauri.conf.json (src-tauri)
Find your triplerustc --print host-tuple
PermissionsFile must be executable (chmod +x on Unix)