Skip to content

Formatters & Code

Vue 3 + Pinia Store Generator

Typed Pinia stores with state, getters and actions.

Runs in your browser
stores/user.ts
lines: 26chars: 431size: 431 B
live

Understanding Vue + Pinia stores

State, derived state, mutations — one defineStore call.

Pinia's setup-style stores, how they replaced Vuex, and the typed-by-construction property that makes them ergonomic.

Pinia is the official Vuex successor.

Pinia (2021) replaced Vuex as Vue's recommended state management as of Vue 3. Same conceptual idea (centralised stores for shared state), much smaller API. Vuex had mutations, actions, getters as three separate concepts; Pinia collapses them into one. Modern Vue projects use Pinia exclusively; Vuex remains for migration in older codebases.

Setup-style stores.

The recommended Pinia syntax mirrors Vue 3's Composition API. State is ref or reactive; computed values are computed; actions are plain functions. The store is a function that returns these. Typed by construction — TypeScript infers the store's shape from what the setup function returns, no boilerplate type declarations needed.

A worked store.

A counter store: import { defineStore } from "pinia"; import { ref, computed } from "vue"; export const useCounterStore = defineStore("counter", () => { const count = ref(0); const doubled = computed(() => count.value * 2); function increment() { count.value++ } return { count, doubled, increment }; }); Three exports from the setup function: a writable ref, a computed derivation, an action. Components import useCounterStore(), get a typed object with all three. No reducers, no dispatch ceremony.

State + computed + action

ref + computed + function

Three pieces, one store.

defineStore('counter', () => ({ count, doubled, increment }))

= Typed, reactive store

Reading a store in a component.

const counter = useCounterStore() in a component's setup gives you a reactive proxy. Use counter.count in the template — Vue's reactivity tracks it. Outside the template (in setup logic), use counter.count directly; the proxy unwraps refs. Destructuring is the trap: const { count } = counter loses reactivity. Use storeToRefs(counter) to keep it.

Persistence and devtools.

Pinia integrates with Vue Devtools out of the box — every store change is visible, time-travel works. For localStorage / sessionStorage persistence, the pinia-plugin-persistedstate package adds one option per store. The plugin model is genuinely simple; writing custom plugins is a handful of lines.

When you don't need Pinia.

For component-local state, use ref directly — no store needed. For shared state across two or three sibling components, use Vue's provide/inject pattern. Pinia is the right answer when the state is truly application-wide (user session, app settings, cross- page caches). Reaching for a global store for one component's data is over- architecture; the rule is "lift state to the highest component that actually needs it, then Pinia only if that's effectively the root".

Frequently asked questions

Quick answers.

Does this support the Composition API?

Yes. You can toggle between the 'Option Store' syntax and the 'Setup Store' syntax, which uses the same pattern as the Vue 3 Composition API.

Is TypeScript supported?

Yes. The generator produces fully typed TypeScript code by default, ensuring your state and actions benefit from autocompletion and type checking.

How do I use the generated store?

After copying the code into your project, you can import the `useStore` function and call it inside your component's `setup` hook or `<script setup>` block.

Is my code data stored on your server?

No. The store structure you define remains entirely within your browser environment. No code or architectural data is ever transmitted or saved externally.

People also search for

Related tools

More in this room.

See all in Formatters & Code