Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Pinia in Nuxt

Pinia is the official store library for Vue; you know it from the Vue course. In Nuxt it is connected through the @pinia/nuxt module, which sets Pinia up for server rendering and passes store state to the browser. Pinia pays off when shared state grows and actions and computed values appear next to the data.

Installing

npx nuxi module add pinia

The command installs the pinia and @pinia/nuxt packages and adds the module to the config:

// nuxt.config.ts
export default defineNuxtConfig({
  compatibilityDate: '2025-07-15',
  modules: ['@pinia/nuxt']
})

After restarting npm run dev, the functions defineStore and storeToRefs are available without an import.

A store

Stores go into the app/stores/ folder. Create app/stores/favorites.ts, the reader's favourite posts:

// app/stores/favorites.ts
export const useFavoritesStore = defineStore('favorites', () => {
  const ids = ref<number[]>([])
 
  const count = computed(() => ids.value.length)
 
  function toggle(id: number) {
    if (ids.value.includes(id)) {
      ids.value = ids.value.filter((item) => item !== id)
    } else {
      ids.value.push(id)
    }
  }
 
  return { ids, count, toggle }
})

This is a setup-style store: a ref becomes state, a computed becomes a getter, and a function becomes an action.

Using it

Add a button to the card app/components/PostCard.vue:

<!-- app/components/PostCard.vue -->
<script setup lang="ts">
defineProps<{
  post: { id: number; title: string; text: string }
}>()
 
const favorites = useFavoritesStore()
</script>
 
<template>
  <article class="post-card">
    <h3>{{ post.title }}</h3>
    <button @click="favorites.toggle(post.id)">
      {{ favorites.ids.includes(post.id) ? 'Remove from favourites' : 'Add to favourites' }}
    </button>
  </article>
</template>

And a counter in the layout header:

<!-- app/layouts/default.vue -->
<script setup lang="ts">
const favorites = useFavoritesStore()
</script>
 
<template>
  <header>
    <NuxtLink to="/posts">Posts</NuxtLink>
    <span>Favourites: {{ favorites.count }}</span>
  </header>
</template>

Mark two posts on /posts and the header shows "Favourites: 2". The module imports stores from app/stores/ automatically; if that does not work in your module version, import explicitly: import { useFavoritesStore } from '~/stores/favorites'.

useState or Pinia

TaskWhat to choose
One or two simple valuesuseState in a composable
Data together with actions and computed valuesPinia
You want to watch changes in DevToolsPinia

Common mistake

Destructuring a store breaks reactivity: after const { count } = useFavoritesStore() the variable count stays at its initial value forever. Access fields through the object (favorites.count) or use storeToRefs: const { count } = storeToRefs(favorites). Actions can be taken out directly: const { toggle } = favorites.

Thanks for reading!

Donate to the site — we work hard for you.