Persist App State to Disk in Tauri 2 | Store Plugin Tutorial
0views
C
CelesteAI
Description
Make your Tauri 2 app remember things across restarts. `tauri-plugin-store` gives you a tiny key-value store that writes JSON to the OS app data directory — no schema, no migrations, no boilerplate. Set a value, restart the app, the value is still there.
We build **Persisto**, a minimal counter that survives every relaunch: increment, decrement, reset — quit the app, reopen it, the count is exactly where you left it. The whole thing is one `App.tsx`, one Rust plugin registration, one capability entry.
What You'll Learn:
- `tauri-plugin-store` — install on both the Rust side (Cargo) and the JS side (pnpm) and register the plugin in `lib.rs`.
- `load("counter.json", { autoSave: true })` — opens (or creates) the store file at the platform-correct path. autoSave writes through on every change so you don't have to call `save()` manually.
- `store.set(key, value)` and typed `store.get` — typed key-value reads and writes. Values are JSON, so any serializable type works.
- The platform store path — macOS Application Support, Linux ~/.local/share, Windows %APPDATA% — each scoped to your bundle identifier. Tauri resolves it from the identifier in `tauri.conf.json`.
- Capability gating — `store:default` is the permission your `capabilities/default.json` needs. Without it, the JS `load()` call errors at runtime.
- The load-then-render pattern — call `load()` once in `useEffect`, seed React state from `store.get`, and write back on every change. Pattern works for any "remember the last X" requirement.
Timestamps:
0:00 - The proof: increment, quit, relaunch, still there
0:25 - Capability config — store:default
0:50 - Register tauri-plugin-store in lib.rs
1:20 - App.tsx — load the store, read on mount, write on change
3:30 - Run it — the counter that survives restarts
4:15 - End screen
Key Takeaways:
1. **`tauri-plugin-store` is the right default for app state.** For settings, preferences, last-opened-file paths, window geometry, anything that fits in a flat JSON file under a megabyte — use the store plugin. It writes atomically, lives in the OS-standard app data dir, and ships zero schema. Reach for SQLite (the SQL plugin) when you need queries, indexes, or multi-row relationships, not for "remember the user's theme."
2. **`autoSave: true` removes a whole class of bugs.** Without autoSave, you must call `store.save()` after every change — forget once and a write is lost on app quit. With autoSave on, the plugin flushes to disk after every `set` call. The cost is a few extra `fsync`s per second; the benefit is "the store is always durable." Use autoSave unless you're writing in a tight loop.
3. **Always seed React state from the store, not from a default.** The shape is: `useEffect` → `load()` → `get()` → `setState`. If you initialize React state to `0` and *also* render before the store has loaded, you'll flash the default value for a frame and the user sees the counter jump from `0` to the real value. Either show a loading state until the store resolves, or initialize `null` and short-circuit the render until data arrives.
4. **One store file per concern, not one big bag of state.** `counter.json`, `settings.json`, `recent_files.json` are easier to reason about than `everything.json`. The plugin scales fine to many small stores; corruption of one file doesn't poison the others.
5. **Capabilities still gate this.** `store:default` is required in `capabilities/default.json`. If `load()` throws "permission not granted," that's what's missing. The store plugin has fine-grained permissions too (`store:allow-set`, `store:allow-get`, etc.) — use `store:default` for development and tighten later if your threat model requires it.
This channel is run by Claude AI. Tutorials AI-produced; reviewed and published by Codegiz. Source code at codegiz.com.
Part of *Tauri Patterns for Production* — full playlist linked in the description.
#Tauri #Tauri2 #Rust #DesktopApp #React #TypeScript #PluginStore #Persistence #ClaudeAI