# How TUUI Integrates Pinia State Persistence with LocalStorage for Configuration Management

> Learn how TUUI integrates Pinia state persistence with localStorage for seamless configuration management. Keep your settings across restarts without manual code. Explore the ai-ql/tuui repo.

- Repository: [AIQL/tuui](https://github.com/ai-ql/tuui)
- Tags: how-to-guide
- Published: 2026-02-23

---

**TUUI uses the `pinia-plugin-state-persistence` plugin to automatically synchronize selected Pinia stores with the browser's `localStorage`, ensuring configuration data survives page refreshes and application restarts without manual serialization logic.**

The ai-ql/tuui repository implements a declarative persistence layer for its Electron-based Vue.js application by integrating Pinia with a dedicated state persistence plugin. This approach allows individual stores to opt-in to localStorage synchronization, providing seamless configuration management for UI preferences, chat history, and runtime settings across the entire application lifecycle.

## Bootstrapping Pinia with the Persistence Plugin

The integration begins during application initialization in [`src/renderer/main.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/main.ts). Here, the Pinia instance is created and enhanced with the persistence plugin before being mounted to the Vue application.

```typescript
// src/renderer/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createStatePersistence } from 'pinia-plugin-state-persistence'

const app = createApp(App)
const pinia = createPinia()
pinia.use(createStatePersistence())   // activates localStorage synchronization
app.use(pinia).mount('#app')

```

The `createStatePersistence()` function wraps each store's state, automatically writing JSON-serialized data to `window.localStorage` on every mutation and restoring values when the application reloads.

## Store-Level Persistence Configuration

Individual stores opt-in to persistence by declaring a `persist` option in their definition passed to `defineStore`. TUUI supports both full-state and selective property persistence, allowing granular control over which configuration data persists across sessions.

### Full State Persistence

The **stdio store** demonstrates complete state persistence for command-line configuration data. In [`src/renderer/store/stdio.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/stdio.ts), the `persist: true` option ensures the entire store state is serialized to localStorage.

```typescript
// src/renderer/store/stdio.ts
export const useStdioStore = defineStore('stdioStore', () => {
  const configValues = ref<Record<string, CustomStdioServerParameters>>({})
  // ... store logic and actions
  
  return { configValues }
}, {
  persist: true               // entire state saved to localStorage
})

```

### Selective Property Persistence

The **locale store** in [`src/renderer/store/locale.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/locale.ts) uses selective persistence to store only the user's language preference while keeping other properties ephemeral.

```typescript
// src/renderer/store/locale.ts
export const useLocaleStore = defineStore('localeStore', {
  state: () => ({
    selected: undefined,
    list: [],
    fallback: {}
  }),
  persist: {
    include: ['selected']      // only persists the chosen language
  }
})

```

This pattern appears across multiple configuration stores in TUUI, including `chatbotStore`, `agentStore`, `historyStore`, and `dxtStore`, each specifying exactly which runtime settings must survive application restarts.

## Underlying Storage Mechanism

The plugin writes data to `window.localStorage` using a deterministic key format that includes versioning for safe migrations:

```

persist:<storeId>-<process.env.NODE_ENV>-<schemaVersion>

```

The `schemaVersion` constant is defined in [`src/main/utils/Constants.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/utils/Constants.ts) and appended to each storage key. This versioning strategy prevents conflicts when the persisted data structure changes between application updates.

When a store initializes, the plugin automatically checks for existing data at its namespaced key (e.g., `persist:localeStore-development-1`), parses the JSON, and hydrates the store state before the first component access. Subsequent mutations trigger immediate re-serialization to localStorage.

## Accessing Persisted Configuration

Application code interacts with persisted stores exactly like standard Pinia stores. The restoration happens transparently during store initialization:

```typescript
const localeStore = useLocaleStore()
console.log(localeStore.selected)   // returns value from localStorage if present

```

This declarative approach eliminates the need for manual localStorage API calls within components or store actions, centralizing persistence logic within the Pinia plugin ecosystem.

## Summary

- **TUUI integrates `pinia-plugin-state-persistence`** during bootstrap in [`src/renderer/main.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/main.ts) to enable automatic localStorage synchronization across all Pinia stores.
- **Stores opt-in via the `persist` option**, supporting both full-state persistence (`persist: true`) and selective property filtering (`persist: { include: [...] }`).
- **Configuration stores** like `localeStore`, `stdioStore`, `chatbotStore`, `agentStore`, `historyStore`, and `dxtStore` leverage this system to preserve user preferences and runtime settings across Electron app restarts.
- **Versioned storage keys** using `schemaVersion` from [`src/main/utils/Constants.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/utils/Constants.ts) ensure safe data migration when configuration schemas evolve.

## Frequently Asked Questions

### How does TUUI persist Pinia state to localStorage?

TUUI registers the `pinia-plugin-state-persistence` plugin during application initialization in [`src/renderer/main.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/main.ts). This plugin wraps each Pinia store and automatically serializes state mutations to `window.localStorage` as JSON strings, then restores them when the application reloads.

### Can I persist only specific properties of a Pinia store in TUUI?

Yes. Instead of `persist: true`, pass an options object with an `include` array listing the specific state properties to persist. The `localeStore` in [`src/renderer/store/locale.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/locale.ts) demonstrates this by persisting only the `selected` language property while keeping other state ephemeral.

### Where is the persisted data stored in localStorage?

Data is stored under keys following the format `persist:<storeId>-<process.env.NODE_ENV>-<schemaVersion>`. For example, the locale store might use `persist:localeStore-development-1`, where the schema version is imported from [`src/main/utils/Constants.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/utils/Constants.ts).

### How does TUUI handle schema changes in persisted configuration?

TUUI uses a `schemaVersion` constant defined in [`src/main/utils/Constants.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/utils/Constants.ts) that is appended to every localStorage key. When the data structure changes, incrementing this version forces the application to use a fresh storage key, preventing deserialization errors from outdated cached data.