Skip to content

Pinia Instance ​

The Pinia instance is the central hub that manages all stores in your application. It's created with createPinia() and installed as a Vue plugin.

Creating a Pinia Instance ​

createPinia() ​

Creates a new Pinia instance.

Signature ​

ts
function createPinia(): Pinia

Example ​

js
import { createPinia } from 'pinia'
import { createApp } from 'vue'

const app = createApp({})
const pinia = createPinia()

app.use(pinia)

Properties ​

install ​

  • Type: (app: App, ...options: any[]) => any

Vue plugin install function. Automatically called when using app.use(pinia).

state ​

  • Type: Ref<Record<string, StateTree>>
  • Read only

Reactive object containing the state of all stores. Mainly used internally and for devtools.

js
const pinia = createPinia()
console.log(pinia.state.value) // { user: { ... }, cart: { ... } }

Methods ​

use() ​

Adds a plugin to the Pinia instance. Plugins are applied to all stores created after the plugin is added.

Signature ​

ts
use(plugin: PiniaPlugin): Pinia

Parameters ​

  • plugin: A function that receives a context object and optionally returns properties to add to stores

Example ​

js
import { createPinia } from 'pinia'

const pinia = createPinia()

// Add a simple plugin
pinia.use(({ store }) => {
  store.hello = 'world'
})

// Add a plugin with options
function createLoggerPlugin(options = {}) {
  return ({ store }) => {
    if (options.enabled) {
      store.$onAction(({ name, args }) => {
        console.log(`Action ${name} called with:`, args)
      })
    }
  }
}

pinia.use(createLoggerPlugin({ enabled: true }))

_s (Internal) ​

  • Type: Map<string, StoreGeneric>
  • Internal use only

Map containing all registered stores. Used internally by Pinia.

_e (Internal) ​

  • Type: EffectScope
  • Internal use only

Effect scope for the Pinia instance. Used internally for cleanup.

Plugin System ​

Plugin Context ​

When creating a plugin, you receive a context object with the following properties:

ts
interface PiniaPluginContext {
  pinia: Pinia
  app: App
  store: Store
  options: DefineStoreOptions
}

Properties ​

  • pinia: The Pinia instance
  • app: The Vue application instance (Vue 3 only)
  • store: The store being augmented
  • options: The options object passed to defineStore()

Plugin Examples ​

Simple Property Plugin ​

js
function addSecretPlugin() {
  return { secret: 'the cake is a lie' }
}

pinia.use(addSecretPlugin)

Router Plugin ​

js
import { markRaw } from 'vue'
import { router } from './router'

function routerPlugin({ store }) {
  store.router = markRaw(router)
}

pinia.use(routerPlugin)

Persistence Plugin ​

js
import { watch } from 'vue'

function persistencePlugin({ store }) {
  const storageKey = `pinia-${store.$id}`
  
  // Restore from localStorage
  const saved = localStorage.getItem(storageKey)
  if (saved) {
    store.$patch(JSON.parse(saved))
  }
  
  // Save to localStorage on changes
  watch(
    () => store.$state,
    (state) => {
      localStorage.setItem(storageKey, JSON.stringify(state))
    },
    { deep: true }
  )
}

pinia.use(persistencePlugin)

TypeScript ​

Typing Plugins ​

ts
import type { PiniaPluginContext } from 'pinia'

function myPlugin(context: PiniaPluginContext) {
  // Plugin implementation
}

Extending Store Properties ​

When adding properties to stores via plugins, extend the PiniaCustomProperties interface:

ts
import 'pinia'

declare module 'pinia' {
  export interface PiniaCustomProperties {
    router: Router
    secret: string
  }
}

Extending Store State ​

For state properties, extend PiniaCustomStateProperties:

ts
import 'pinia'

declare module 'pinia' {
  export interface PiniaCustomStateProperties<S> {
    lastUpdated: Date
  }
}

SSR Support ​

Server-Side ​

js
// server.js
import { createPinia } from 'pinia'
import { createSSRApp } from 'vue'

export function createApp() {
  const app = createSSRApp({})
  const pinia = createPinia()
  
  app.use(pinia)
  
  return { app, pinia }
}

Client-Side Hydration ​

js
// client.js
import { createApp } from './main'

const { app, pinia } = createApp()

// Hydrate state from server
if (window.__PINIA_STATE__) {
  pinia.state.value = window.__PINIA_STATE__
}

app.mount('#app')

Testing ​

Creating Test Instances ​

js
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach } from 'vitest'

beforeEach(() => {
  const pinia = createPinia()
  setActivePinia(pinia)
})

Mocking Plugins ​

js
import { createPinia } from 'pinia'

const pinia = createPinia()

// Mock plugin for testing
pinia.use(() => ({
  $api: {
    get: vi.fn(),
    post: vi.fn()
  }
}))

Best Practices ​

Plugin Order ​

js
const pinia = createPinia()

// Add plugins in order of dependency
pinia.use(routerPlugin) // Base functionality
pinia.use(persistencePlugin) // Depends on state
pinia.use(loggerPlugin) // Should be last for complete logging

Conditional Plugins ​

js
const pinia = createPinia()

// Development-only plugins
if (process.env.NODE_ENV === 'development') {
  pinia.use(loggerPlugin)
  pinia.use(devtoolsPlugin)
}

// Production-only plugins
if (process.env.NODE_ENV === 'production') {
  pinia.use(analyticsPlugin)
}

Plugin Configuration ​

js
// Create configurable plugins
function createApiPlugin(baseURL) {
  return ({ store }) => {
    store.$api = createApiClient(baseURL)
  }
}

const pinia = createPinia()
pinia.use(createApiPlugin('https://api.example.com'))

Lifecycle ​

Installation ​

  1. createPinia() creates a new instance
  2. app.use(pinia) installs the plugin
  3. Pinia sets up global properties and provides the instance

Store Creation ​

  1. defineStore() registers store definition
  2. First call to useStore() creates the store instance
  3. Plugins are applied to the new store
  4. Store is added to the Pinia instance

Cleanup ​

  1. When the app unmounts, Pinia cleans up all stores
  2. Effect scopes are disposed
  3. Subscriptions are removed

See Also ​

Released under the MIT License.