Skip to content
Documentation GitHub
Architecture

Tauri Dev/Prod Resource Resolution Pattern

Tauri Dev/Prod Resource Resolution Pattern

Problem

Tauri desktop apps need to locate bundled resources (binaries, scripts, config files) at runtime. The file layout differs between dev mode (source tree) and production (app bundle), leading to path resolution failures when a single hardcoded path is used.

Symptoms:

  • Binary/script found in dev but None/missing in production
  • env!("CARGO_MANIFEST_DIR") works at compile time but doesn’t exist in production
  • Resources placed in storage_dir that should come from the source tree in dev

Root Cause

Tauri apps have two fundamentally different resource layouts:

Resource TypeDev Mode LocationProduction Location
Binaries (ollama, uv)src-tauri/binaries/App.app/Contents/Resources/binaries/
Python sidecarapps/python-sidecar/ (PyInstaller binary)App.app/Contents/MacOS/ (Tauri externalBin)

Using storage_dir.join("resources") for everything fails in dev (those files don’t exist there), and using CARGO_MANIFEST_DIR fails in production (it’s a compile-time constant pointing to the build machine).

Solution

1. Centralize Path Resolution in AppPaths

Add environment-aware methods to the existing AppPaths struct:

paths.rs
const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
impl AppPaths {
/// Bundled binaries (ollama, uv) — downloaded via dev scripts, bundled in prod.
pub fn binaries_dir(&self) -> PathBuf {
if self.is_dev {
PathBuf::from(MANIFEST_DIR).join("binaries")
} else {
self.storage_dir.join("binaries")
}
}
}

2. Use AppPaths in State Initialization

// state.rs — all paths resolved from AppPaths, not hardcoded
let binaries_dir = paths.binaries_dir();
let ollama_binary = resolve_binary_in(&binaries_dir);

3. Configure Tauri Resource Bundling

// tauri.conf.json — maps source paths to bundle paths
{
"bundle": {
"resources": {
"binaries/*": "binaries/"
}
}
}

4. Dev Scripts Populate Gitignored Directories

Terminal window
# tools/dev/download-uv.sh — downloads to gitignored binaries/
# tools/dev/download-ollama.sh — same pattern
# Both follow: detect platform → download → extract → verify → place in binaries/

Implementation Notes

  • binaries/ is gitignored — never check in large binaries. Dev scripts download them.
  • Graceful degradation — all resolution functions return Option<PathBuf> or check exists(). Missing binary = feature unavailable, not crash.
  • Resolution helper pattern — each module exposes a resolve_binary_in(dir: &Path) -> Option<PathBuf> that checks existence without knowing about dev/prod.
  • Tests verify dev pathstest_agent_scripts_dir_dev asserts the resolved path actually contains the expected file.

Prevention

Best Practices

  • Never hardcode paths — always go through AppPaths methods
  • One source of truth per resource type — binaries_dir for binaries, agent_scripts_dir for scripts
  • Dev scripts mirror production — if it’s bundled in prod, there’s a download script for dev
  • Test both directions — unit test that dev path resolves, integration test that the resource exists there

Warning Signs

  • PathBuf::from(env!("CARGO_MANIFEST_DIR")) used directly in non-paths.rs code
  • storage_dir.join("some_file") for a file that comes from the source tree
  • Binary/script works on one developer’s machine but not another’s (forgot to run download script)

References

  • apps/desktop/src-tauri/src/paths.rs — AppPaths with binaries_dir() and agent_scripts_dir()
  • apps/desktop/src-tauri/src/ollama_manager.rs — resolve_binary_in() pattern
  • apps/desktop/src-tauri/tauri.conf.json — resource bundling config
  • tools/dev/download-uv.sh, tools/dev/download-ollama.sh — dev binary download scripts

Was this page helpful?