Skip to content
Back to skills

Tauri App Resources

ASecurity

Assists with managing Tauri application resources including app icons setup and generation, embedding static files and assets, accessing bundled resources at runtime, and implementing thread-safe state management patterns.

  • 33 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added February 8, 2026
developmentjavascriptrustgojavabashapifrontend

Works with

  • api

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add dchuk/claude-code-tauri-skills --skill tauri-app-resources --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tauri App Resources?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Tauri App Resources
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dchuk-tauri-app-resources/badge)](https://www.skillsdirectory.com/skills/dchuk-tauri-app-resources)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: managing-tauri-app-resources
description: Assists with managing Tauri application resources including app icons setup and generation, embedding static files and assets, accessing bundled resources at runtime, and implementing thread-safe state management patterns.
---

# Managing Tauri App Resources

## App Icons

### Icon Generation

Generate all platform-specific icons from a single source file:

```bash
cargo tauri icon              # Default: ./app-icon.png
cargo tauri icon ./custom.png -o ./icons  # Custom source/output
cargo tauri icon --ios-color "#000000"    # iOS background color
```

**Source requirements:** Squared PNG or SVG with transparency.

### Generated Formats

| Format | Platform |
|--------|----------|
| `icon.icns` | macOS |
| `icon.ico` | Windows |
| `*.png` | Linux, Android, iOS |

### Configuration

```json
{
  "bundle": {
    "icon": [
      "icons/32x32.png",
      "icons/128x128.png",
      "icons/128x128@2x.png",
      "icons/icon.icns",
      "icons/icon.ico"
    ]
  }
}
```

### Platform Requirements

**Windows (.ico):** Layers for 16, 24, 32, 48, 64, 256 pixels.

**Android:** No transparency. Place in `src-tauri/gen/android/app/src/main/res/mipmap-*` folders. Each needs `ic_launcher.png`, `ic_launcher_round.png`, `ic_launcher_foreground.png`.

**iOS:** No transparency. Place in `src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/`. Required sizes: 20, 29, 40, 60, 76, 83.5 pixels with 1x/2x/3x scales, plus 512x512@2x.

---

## Embedding Static Resources

### Configuration

**Array syntax** (preserves directory structure):

```json
{
  "bundle": {
    "resources": ["./file.txt", "folder/", "docs/**/*.md"]
  }
}
```

**Map syntax** (custom destinations):

```json
{
  "bundle": {
    "resources": {
      "path/to/source.json": "resources/dest.json",
      "docs/**/*.md": "website-docs/"
    }
  }
}
```

### Path Patterns

| Pattern | Behavior |
|---------|----------|
| `"dir/file.txt"` | Single file |
| `"dir/"` | Directory recursive |
| `"dir/*"` | Files non-recursive |
| `"dir/**/*"` | All files recursive |

### Accessing Resources - Rust

```rust
use tauri::Manager;
use tauri::path::BaseDirectory;

#[tauri::command]
fn load_resource(handle: tauri::AppHandle) -> Result<String, String> {
    let path = handle
        .path()
        .resolve("lang/de.json", BaseDirectory::Resource)
        .map_err(|e| e.to_string())?;
    std::fs::read_to_string(&path).map_err(|e| e.to_string())
}
```

### Accessing Resources - JavaScript

```javascript
import { resolveResource } from '@tauri-apps/api/path';
import { readTextFile } from '@tauri-apps/plugin-fs';

const resourcePath = await resolveResource('lang/de.json');
const content = await readTextFile(resourcePath);
const data = JSON.parse(content);
```

### Permissions

```json
{
  "permissions": [
    "fs:allow-read-text-file",
    "fs:allow-resource-read-recursive"
  ]
}
```

Use `$RESOURCE/**/*` scope for recursive access.

---

## State Management

### Basic Setup

```rust
use tauri::{Builder, Manager};

struct AppData {
    welcome_message: &'static str,
}

fn main() {
    Builder::default()
        .setup(|app| {
            app.manage(AppData {
                welcome_message: "Welcome!",
            });
            Ok(())
        })
        .run(tauri::generate_context!())
        .unwrap()
}
```

### Thread-Safe Mutable State

```rust
use std::sync::Mutex;
use tauri::{Builder, Manager};

#[derive(Default)]
struct AppState {
    counter: u32,
}

fn main() {
    Builder::default()
        .setup(|app| {
            app.manage(Mutex::new(AppState::default()));
            Ok(())
        })
        .run(tauri::generate_context!())
        .unwrap()
}
```

### Accessing State in Commands

```rust
use std::sync::Mutex;
use tauri::State;

#[tauri::command]
fn increase_counter(state: State<'_, Mutex<AppState>>) -> u32 {
    let mut state = state.lock().unwrap();
    state.counter += 1;
    state.counter
}

#[tauri::command]
fn get_counter(state: State<'_, Mutex<AppState>>) -> u32 {
    state.lock().unwrap().counter
}
```

### Async Commands with Tokio Mutex

```rust
use tokio::sync::Mutex;
use tauri::State;

#[tauri::command]
async fn increase_counter_async(
    state: State<'_, Mutex<AppState>>
) -> Result<u32, ()> {
    let mut state = state.lock().await;
    state.counter += 1;
    Ok(state.counter)
}
```

### Accessing State Outside Commands

```rust
use std::sync::Mutex;
use tauri::{Manager, Window, WindowEvent};

fn on_window_event(window: &Window, event: &WindowEvent) {
    let app_handle = window.app_handle();
    let state = app_handle.state::<Mutex<AppState>>();
    let mut state = state.lock().unwrap();
    state.counter += 1;
}
```

### Type Alias Pattern

Prevent runtime panics from type mismatches:

```rust
use std::sync::Mutex;

struct AppStateInner {
    counter: u32,
}

type AppState = Mutex<AppStateInner>;

#[tauri::command]
fn get_counter(state: State<'_, AppState>) -> u32 {
    state.lock().unwrap().counter
}
```

### Multiple State Types

```rust
use std::sync::Mutex;
use tauri::{Builder, Manager, State};

struct UserState { username: Option<String> }
struct AppSettings { theme: String }

fn main() {
    Builder::default()
        .setup(|app| {
            app.manage(Mutex::new(UserState { username: None }));
            app.manage(Mutex::new(AppSettings { theme: "dark".into() }));
            Ok(())
        })
        .run(tauri::generate_context!())
        .unwrap()
}

#[tauri::command]
fn login(user_state: State<'_, Mutex<UserState>>, username: String) {
    user_state.lock().unwrap().username = Some(username);
}

#[tauri::command]
fn set_theme(settings: State<'_, Mutex<AppSettings>>, theme: String) {
    settings.lock().unwrap().theme = theme;
}
```

### Key Points

- **Arc not required** - Tauri handles reference counting internally
- **Use std::sync::Mutex** for most cases; Tokio's mutex only for holding locks across await points
- **Type safety** - Wrong state types cause runtime panics, not compile errors; use type aliases

---

## Complete Example

**tauri.conf.json:**

```json
{
  "bundle": {
    "icon": [
      "icons/32x32.png",
      "icons/128x128.png",
      "icons/icon.icns",
      "icons/icon.ico"
    ],
    "resources": {
      "assets/config.json": "config.json",
      "assets/translations/": "lang/"
    }
  }
}
```

**src-tauri/src/main.rs:**

```rust
use std::sync::Mutex;
use serde::{Deserialize, Serialize};
use tauri::{Builder, Manager, State};
use tauri::path::BaseDirectory;

#[derive(Default)]
struct AppState { counter: u32, locale: String }
type ManagedState = Mutex<AppState>;

#[derive(Serialize, Deserialize)]
struct Config { app_name: String, version: String }

#[tauri::command]
fn increment(state: State<'_, ManagedState>) -> u32 {
    let mut s = state.lock().unwrap();
    s.counter += 1;
    s.counter
}

#[tauri::command]
fn load_config(handle: tauri::AppHandle) -> Result<Config, String> {
    let path = handle.path()
        .resolve("config.json", BaseDirectory::Resource)
        .map_err(|e| e.to_string())?;
    let content = std::fs::read_to_string(&path).map_err(|e| e.to_string())?;
    serde_json::from_str(&content).map_err(|e| e.to_string())
}

fn main() {
    Builder::default()
        .setup(|app| {
            app.manage(Mutex::new(AppState::default()));
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![increment, load_config])
        .run(tauri::generate_context!())
        .unwrap()
}
```

**Frontend:**

```javascript
import { invoke } from '@tauri-apps/api/core';
import { resolveResource } from '@tauri-apps/api/path';
import { readTextFile } from '@tauri-apps/plugin-fs';

const newValue = await invoke('increment');
const config = await invoke('load_config');
const langPath = await resolveResource('lang/en.json');
const translations = JSON.parse(await readTextFile(langPath));
```

---

## Quick Reference

### Icon Commands
```bash
cargo tauri icon                    # Generate from ./app-icon.png
cargo tauri icon ./icon.png -o out  # Custom source/output
```

### Resource Patterns
```json
{ "resources": ["data.json"] }              // Single file
{ "resources": ["assets/"] }                // Directory recursive
{ "resources": { "src/x.json": "x.json" }}  // Custom destination
```

### State Patterns
```rust
app.manage(Config { ... });              // Immutable
app.manage(Mutex::new(State { ... }));   // Mutable
fn cmd(state: State<'_, Mutex<T>>)       // In command
app_handle.state::<Mutex<T>>()           // Via AppHandle
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.