zudo-tauri

Type to search...

to open search from anywhere

macOS Deployment Pitfalls

CreatedMar 29, 2026UpdatedMar 29, 2026Takeshi Takatsudo

Critical macOS-specific deployment issues that cause subtle, hard-to-debug failures

macOS Deployment Pitfalls

This page documents the single most frustrating debugging issue in Tauri macOS deployment. If you spend hours wondering why your latest code changes are not taking effect after a build, this is almost certainly why.

The #1 Pitfall: cp -rf is BROKEN for .app Bundles

⚠️ Warning

Never use cp -rf to overwrite an existing .app bundle. Always remove the old .app first, then copy.

# WRONG - binary inside stays stale
cp -rf target/release/bundle/macos/MyApp.app /Applications/

# CORRECT - remove first, then copy
rm -rf /Applications/MyApp.app
cp -r target/release/bundle/macos/MyApp.app /Applications/

Why This Happens

A .app bundle is a directory structure:

MyApp.app/
  Contents/
    MacOS/
      MyApp              <-- The actual binary
    Resources/
      ...
    Info.plist

When you cp -rf a new .app over an existing one, macOS’s cp command behaves unexpectedly:

  • It copies new and changed files into the existing directory
  • But the binary inside Contents/MacOS/ may not be replaced if it is currently in use, cached by the kernel, or has certain file flags
  • The result: the .app bundle looks new (new Info.plist, new resources), but the actual executable is the old version

You end up running old code with new metadata, which produces incredibly confusing behavior. Your changes are not showing up, your logs say the right version, but the behavior is wrong.

The Correct Procedure

Always follow this sequence:

# 1. Kill the running app (if any)
killall MyApp 2>/dev/null || true

# 2. Wait briefly for process to exit
sleep 1

# 3. Remove the old bundle completely
rm -rf /Applications/MyApp.app

# 4. Copy the fresh bundle
cp -r target/release/bundle/macos/MyApp.app /Applications/

# 5. Clear quarantine
xattr -cr /Applications/MyApp.app

Verify the Binary is Fresh

After installing, verify that the binary timestamp matches your build:

# Check when the binary was last modified
stat -f "%Sm" /Applications/MyApp.app/Contents/MacOS/MyApp

# Compare with the source
stat -f "%Sm" target/release/bundle/macos/MyApp.app/Contents/MacOS/MyApp

Both timestamps should be identical (or within seconds of each other). If the /Applications/ binary has an older timestamp, the copy did not work correctly.

💡 Tip

Create a shell alias or script for the install procedure so you never accidentally use cp -rf:

# ~/.zshrc
install-tauri() {
  local app_name="${1:?Usage: install-tauri AppName}"
  killall "$app_name" 2>/dev/null || true
  sleep 1
  rm -rf "/Applications/${app_name}.app"
  cp -r "target/release/bundle/macos/${app_name}.app" /Applications/
  xattr -cr "/Applications/${app_name}.app"
  echo "Installed ${app_name}.app"
}

Other macOS Issues

App Translocation

macOS may “translocate” apps that are opened for the first time from certain locations (like the Downloads folder). Translocation copies the app to a random temporary directory and runs it from there, which breaks relative paths.

Clearing the quarantine attribute with xattr -cr prevents this:

xattr -cr /Applications/MyApp.app

Gatekeeper Warnings

Unsigned apps trigger Gatekeeper warnings. For development, you can bypass this by:

  1. Right-clicking the app and selecting “Open” (instead of double-clicking)
  2. Or clearing extended attributes: xattr -cr /Applications/MyApp.app

For distribution, you will need to sign and notarize the app through Apple’s developer program.

Binary Code Signature

Even in development, if you modify the binary inside the .app bundle after it was created by Tauri, the code signature becomes invalid. macOS may refuse to run the app or show a “damaged” error.

If you see this after a correct install, try:

codesign --remove-signature /Applications/MyApp.app
xattr -cr /Applications/MyApp.app

Summary Checklist

Before reporting “my changes are not showing up”:

  1. Did you rm -rf the old .app before copying? (Not cp -rf)
  2. Did you killall the running app first?
  3. Do the binary timestamps match between source and installed?
  4. Did you clear quarantine with xattr -cr?
  5. Did you verify the frontend assets are actually embedded? (See Cargo Cache)