All skills
vuejs-ai avatar

/vue-pinia-best-practices

@bc922e4 official
by Vue AIvuejs-ai/skills2.9k stars
167

Pinia stores, state management patterns, store setup, and reactivity with stores.

Use this Skill: https://skilld.dev/gh/vuejs-ai/skills/vue-pinia-best-practices

This session only. Nothing lands on disk.

referencepinia-no-active-pinia-error.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Fix "No Active Pinia" Error - Store Setup Timing

Impact: HIGH - The error "getActivePinia() was called but there was no active Pinia" is one of the most common Pinia errors. It occurs when you try to use a store before Pinia has been installed on the Vue app, causing your application to crash.

Task Checklist

  • Ensure app.use(pinia) is called before app.mount()
  • Ensure app.use(pinia) is called before app.use(router) if router guards use stores
  • Never call useXxxStore() in module-level (top-level) code
  • Only call useXxxStore() inside setup functions, composables, or after app initialization
  • Check for <script setup> vs <script> - the latter runs too early

The Error

[🍍]: "getActivePinia()" was called but there was no active Pinia.
Did you forget to install pinia?

Common Cause 1: Wrong Plugin Order

// main.js - WRONG ORDER
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'  // Router uses a store in navigation guard
import App from './App.vue'

const app = createApp(App)

// WRONG: Router is installed first, but its guards use stores
app.use(router)  // Router guard calls useAuthStore() - FAILS!
app.use(createPinia())
app.mount('#app')

Fix: Install Pinia first:

// main.js - CORRECT ORDER
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'

const app = createApp(App)

// CORRECT: Pinia installed before anything that uses stores
app.use(createPinia())
app.use(router)  // Now router guards can safely use stores
app.mount('#app')

Common Cause 2: Store Used at Module Level

// api.js - WRONG: Module-level store usage
import { useAuthStore } from '@/stores/auth'

// This runs immediately when the module is imported!
const authStore = useAuthStore()  // ERROR: No active Pinia yet

export function fetchUser() {
  return fetch('/api/user', {
    headers: {
      Authorization: `Bearer ${authStore.token}`
    }
  })
}

Fix: Call useStore inside functions:

// api.js - CORRECT: Store used inside function
import { useAuthStore } from '@/stores/auth'

export function fetchUser() {
  // Store is accessed when function is called, not when module loads
  const authStore = useAuthStore()

  return fetch('/api/user', {
    headers: {
      Authorization: `Bearer ${authStore.token}`
    }
  })
}

Common Cause 3: Script Tag Missing "setup"

<!-- WRONG: <script> runs before component setup -->
<script>
import { useUserStore } from '@/stores/user'

// This runs too early, before the component is set up
const userStore = useUserStore()  // ERROR!

export default {
  // ...
}
</script>

Fix: Use <script setup> or move to setup function:

<!-- CORRECT: <script setup> runs at the right time -->
<script setup>
import { useUserStore } from '@/stores/user'

// This runs during component setup, Pinia is active
const userStore = useUserStore()  // Works!
</script>
<!-- CORRECT: Options API with setup function -->
<script>
import { useUserStore } from '@/stores/user'

export default {
  setup() {
    // Called during component initialization
    const userStore = useUserStore()  // Works!
    return { userStore }
  }
}
</script>

Common Cause 4: mapStores with Parentheses

<script>
import { mapStores } from 'pinia'
import { useProductsStore } from '@/stores/products'

export default {
  computed: {
    // WRONG: Called the function instead of passing it
    ...mapStores(useProductsStore())  // ERROR!
  }
}
</script>

Fix: Pass the function reference, not the result:

<script>
import { mapStores } from 'pinia'
import { useProductsStore } from '@/stores/products'

export default {
  computed: {
    // CORRECT: Pass the function without calling it
    ...mapStores(useProductsStore)  // No parentheses!
  }
}
</script>

Common Cause 5: Router Guards Before Pinia

// router/index.js - WRONG
import { createRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'

const router = createRouter({ /* ... */ })

// This guard is registered immediately
router.beforeEach((to) => {
  // When this runs during app startup, Pinia might not be ready
  const authStore = useAuthStore()  // May fail!

  if (to.meta.requiresAuth && !authStore.isLoggedIn) {
    return '/login'
  }
})

Fix: Use lazy store access or ensure plugin order:

// router/index.js - CORRECT
import { createRouter } from 'vue-router'

const router = createRouter({ /* ... */ })

router.beforeEach((to) => {
  // Dynamically import to avoid module-level execution
  const { useAuthStore } = await import('@/stores/auth')
  const authStore = useAuthStore()

  if (to.meta.requiresAuth && !authStore.isLoggedIn) {
    return '/login'
  }
})

// OR ensure main.js has correct order:
// app.use(pinia)
// app.use(router)

Debugging Checklist

When you see "No active Pinia":

  1. Check main.js order: Is app.use(pinia) before other plugins?
  2. Search for top-level useStore calls: Any store usage outside functions/setup?
  3. Check script tags: Using <script> instead of <script setup>?
  4. Check mapStores usage: Using useStore() instead of useStore?
  5. Check import chains: Does an early import trigger store usage?

Safe Pattern: Conditional Store Access

// For code that might run before Pinia is ready
import { getActivePinia } from 'pinia'

export function safelyUseStore() {
  const pinia = getActivePinia()

  if (!pinia) {
    console.warn('Pinia not initialized yet')
    return null
  }

  const { useUserStore } = await import('@/stores/user')
  return useUserStore()
}

Reference

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides educational content and best practices for Pinia state management in Vue.js applications. It is a documentation-focused skill with no malicious patterns detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    7 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at bc922e4. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 8 months ago
version
1.0.0
author
github.com/vuejs-ai
  • Vue
  • pinia
  • state-management
  • reactivity
  • store-setup
  • devtools
  • ssr

README badge

README badge for vuejs-ai/skills/vue-pinia-best-practices

Provides Pinia store setup patterns, reactivity gotchas, and state management conventions for Vue apps. Covers destructuring pitfalls, DevTools integration, SSR considerations, and filter persistence strategies.

Generated from the current SKILL.md.

Does this skill cover setup stores and options stores?
Yes. The skill addresses both patterns, including common issues like setup stores missing state in DevTools or SSR, and provides guidance on when to use each.
What reactivity issues does this skill handle?
It covers store destructuring breaking reactivity, method binding losing context in templates, and how to maintain reactive updates when accessing store properties.
Does this skill address SSR or DevTools integration?
Yes. It includes troubleshooting for setup stores not exposing state correctly in DevTools and SSR environments.
Does this cover ephemeral state like filters or URL sync?
Yes. The skill includes patterns for handling filters that reset on refresh and guidance on syncing state with URLs for shareable application state.

Generated from the current SKILL.md. These answers refresh after source changes.