zudo-tauri

Type to search...

to open search from anywhere

Bundling Node.js

CreatedMar 29, 2026UpdatedMar 29, 2026Takeshi Takatsudo

Download script for including a standalone Node.js binary with your Tauri app

Bundling Node.js

Some Tauri apps need to run Node.js as a sidecar process (for example, to run a dev server or a build tool). Rather than requiring the user to have Node.js installed, you can bundle a standalone Node.js binary with your app.

Why Bundle Node.js

  • No user-side dependency — the app works out of the box
  • Version pinning — you control exactly which Node.js version runs
  • Reproducibility — no surprises from different Node.js versions on different machines

Download Script

The following bash script downloads a Node.js standalone binary for the target platform, verifies its SHA256 checksum, extracts it, and renames the binary with a target triple suffix (which Tauri requires for sidecar binaries).

#!/bin/bash
set -euo pipefail

# Configuration
NODE_VERSION="v20.11.1"
NODE_BASE_URL="https://nodejs.org/dist/${NODE_VERSION}"

# Detect platform
ARCH=$(uname -m)
OS=$(uname -s | tr '[:upper:]' '[:lower:]')

case "$ARCH" in
  x86_64)  NODE_ARCH="x64" ;;
  arm64)   NODE_ARCH="arm64" ;;
  aarch64) NODE_ARCH="arm64" ;;
  *)
    echo "Unsupported architecture: $ARCH"
    exit 1
    ;;
esac

case "$OS" in
  darwin) NODE_OS="darwin" ;;
  linux)  NODE_OS="linux" ;;
  *)
    echo "Unsupported OS: $OS"
    exit 1
    ;;
esac

TARBALL="node-${NODE_VERSION}-${NODE_OS}-${NODE_ARCH}.tar.gz"
DOWNLOAD_URL="${NODE_BASE_URL}/${TARBALL}"
SHASUMS_URL="${NODE_BASE_URL}/SHASUMS256.txt"

# Target triple for Tauri sidecar naming
case "$OS-$ARCH" in
  darwin-arm64)  TARGET_TRIPLE="aarch64-apple-darwin" ;;
  darwin-x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;;
  linux-x86_64)  TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;;
  linux-aarch64) TARGET_TRIPLE="aarch64-unknown-linux-gnu" ;;
  linux-arm64)   TARGET_TRIPLE="aarch64-unknown-linux-gnu" ;;
  *)
    echo "Unsupported platform: $OS-$ARCH"
    exit 1
    ;;
esac

# Output directory
BINARIES_DIR="./binaries"
mkdir -p "$BINARIES_DIR"

echo "Downloading Node.js ${NODE_VERSION} for ${NODE_OS}-${NODE_ARCH}..."

# Download tarball
curl -fsSL "$DOWNLOAD_URL" -o "/tmp/${TARBALL}"

# Download and verify SHA256
echo "Verifying SHA256 checksum..."
EXPECTED_SHA=$(curl -fsSL "$SHASUMS_URL" | grep "$TARBALL" | awk '{print $1}')

if [ -z "$EXPECTED_SHA" ]; then
  echo "ERROR: Could not find SHA256 for $TARBALL"
  exit 1
fi

ACTUAL_SHA=$(shasum -a 256 "/tmp/${TARBALL}" | awk '{print $1}')

if [ "$EXPECTED_SHA" != "$ACTUAL_SHA" ]; then
  echo "ERROR: SHA256 mismatch!"
  echo "  Expected: $EXPECTED_SHA"
  echo "  Actual:   $ACTUAL_SHA"
  rm -f "/tmp/${TARBALL}"
  exit 1
fi

echo "SHA256 verified: $ACTUAL_SHA"

# Extract the node binary
echo "Extracting node binary..."
tar -xzf "/tmp/${TARBALL}" \
  -C /tmp \
  "node-${NODE_VERSION}-${NODE_OS}-${NODE_ARCH}/bin/node"

# Move and rename with target triple
OUTPUT_NAME="node-${TARGET_TRIPLE}"
mv "/tmp/node-${NODE_VERSION}-${NODE_OS}-${NODE_ARCH}/bin/node" \
   "${BINARIES_DIR}/${OUTPUT_NAME}"

# Make executable
chmod +x "${BINARIES_DIR}/${OUTPUT_NAME}"

# Clean up
rm -rf "/tmp/${TARBALL}" \
       "/tmp/node-${NODE_VERSION}-${NODE_OS}-${NODE_ARCH}"

echo "Done: ${BINARIES_DIR}/${OUTPUT_NAME}"
ls -lh "${BINARIES_DIR}/${OUTPUT_NAME}"

Usage

Save the script as scripts/download-node.sh and run it:

chmod +x scripts/download-node.sh
./scripts/download-node.sh

This creates:

binaries/
  node-aarch64-apple-darwin     (on Apple Silicon Mac)
  node-x86_64-apple-darwin      (on Intel Mac)

.gitignore the Binaries

Node.js binaries are large (60-80MB). Do not commit them to git.

# .gitignore
binaries/

Download them as part of your build setup or CI pipeline instead.

Tauri Sidecar Configuration

To use the downloaded Node.js as a Tauri sidecar, add it to tauri.conf.json:

{
  "bundle": {
    "externalBin": [
      "binaries/node"
    ]
  }
}

📝 Note

The externalBin path does not include the target triple suffix. Tauri automatically appends the correct suffix (e.g., -aarch64-apple-darwin) based on the build target. That is why the download script names the binary with the target triple.

Then in your Rust code, invoke it:

use tauri::Manager;
use tauri_plugin_shell::ShellExt;

// Spawn Node.js with a script
let output = app_handle
    .shell()
    .sidecar("node")
    .expect("failed to create sidecar command")
    .args(["server.js"])
    .output()
    .await
    .expect("failed to run node");

SHA256 Verification

The script verifies the download against the official SHA256 checksums published by Node.js at:

https://nodejs.org/dist/v20.11.1/SHASUMS256.txt

This prevents installing a corrupted or tampered binary. If the checksum does not match, the script exits with an error.

⚠️ Warning

Never skip SHA256 verification when downloading binaries. A corrupted Node.js binary can cause subtle, impossible-to-debug runtime errors, or worse, a supply-chain attack.

Multiple Platforms

If you need to bundle Node.js for multiple platforms (e.g., for cross-compilation), run the script once for each target:

# On an Apple Silicon Mac, download for both architectures
./scripts/download-node.sh  # Gets arm64 automatically

# For cross-compilation, modify the script or download manually:
# curl the x86_64 tarball and rename appropriately

The binaries/ directory should contain one binary per target:

binaries/
  node-aarch64-apple-darwin
  node-x86_64-apple-darwin
  node-x86_64-unknown-linux-gnu