Skip to content

Defining a Store

Pinia stores are defined with defineStore. The setup syntax — using the Composition API inside a store — is the modern, recommended style and the one FamilyTree uses.

If you scaffolded with create-vue and selected Pinia, it’s already installed and added to main.ts:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia()) // install Pinia before mounting
app.mount('#app')

If you need to add it manually: npm install pinia.

src/stores/familyStore.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useFamilyStore = defineStore('family', () => {
// state
const people = ref([])
const focusPersonId = ref(null)
// getters (computed)
const focusPerson = computed(() =>
people.value.find(p => p.id === focusPersonId.value)
)
// actions (functions)
function setFocus(id) {
focusPersonId.value = id
}
return { people, focusPersonId, focusPerson, setFocus }
})

The setup syntax is exactly like writing a composable:

  • ref() creates reactive state
  • computed() creates derived getters
  • Regular functions are actions
  • Everything returned is available to components

Pinia store IDs use kebab-case strings: 'family', 'user-settings', 'cart'. The composable function uses use + store name + Store: useFamilyStore, useCartStore.

src/stores/familyStore.ts
export const useFamilyStore = defineStore('family', () => { ... })
// src/stores/userStore.ts
export const useUserStore = defineStore('user', () => { ... })

Store files live in src/stores/. Each store is a separate file. FamilyTree only needs one store — familyStore.ts — because all state is closely related.

The first argument to defineStore ('family') is the store’s ID — a unique string used internally by Pinia for dev tools, persistence, and SSR. It must be unique across all stores.

  1. Create src/stores/counterStore.ts with a count ref, an increment action, and a doubled computed.
  2. Export it as useCounterStore.
  3. In a component, import useCounterStore, call it, and display store.count and store.doubled.
  4. Add a button that calls store.increment() and verify both values update.
  • defineStore('id', setup) creates a Pinia store using the Composition API inside the setup function.
  • ref() = state, computed() = getters, functions = actions — same patterns as component setup.
  • Store composables follow the use[Name]Store convention.
  • Install Pinia with app.use(createPinia()) before app.mount().
  • Everything the setup function returns is accessible on the store instance.