pinia

GitHub

🍍 Intuitive, type safe, light and flexible Store for Vue using the composition api with DevTools support

14,575 stars TypeScript #composition-api#ssr#store#vue#vuex
RAW Doc

Repository: vuejs/pinia


Stars: 14553

README.md

<p align="center">
<a href="https://pinia.vuejs.org" target="_blank" rel="noopener noreferrer">
<img width="180" src="https://pinia.vuejs.org/logo.svg" alt="Pinia logo">
</a>
</p>
<br/>
<p align="center">
<a href="https://npmx.dev/package/pinia"><img src="https://badgen.net/npm/v/pinia/^4" alt="npm package"></a>
<a href="https://github.com/vuejs/pinia/actions/workflows/ci.yml"><img src="https://github.com/vuejs/pinia/actions/workflows/ci.yml/badge.svg" alt="build status"></a>
<a href="https://codecov.io/gh/vuejs/pinia"><img src="https://codecov.io/gh/vuejs/pinia/branch/v4/graph/badge.svg?token=rU2xxQ6BGH"/></a>
</p>
<br/>

Pinia

Intuitive, type safe and flexible Store for Vue

- πŸ’‘ Intuitive
- πŸ”‘ Type Safe
- βš™οΈ Devtools support
- πŸ”Œ Extensible
- πŸ— Modular by design
- πŸ“¦ Extremely light
- ⛰️ Nuxt Module

The latest version of pinia works with Vue 3. See the branch v2 for a version that works with Vue 2.

Pinia is the most similar English pronunciation of the word _pineapple_ in Spanish: _piΓ±a_. A pineapple is in reality a group of individual flowers that join together to create a multiple fruit. Similar to stores, each one is born individually, but they are all connected at the end. It's also a delicious tropical fruit indigenous to South America.

πŸ‘‰ Demo with Vue 3 on StackBlitz

πŸ‘‰ Demo with Nuxt 3 on StackBlitz

Help me keep working on this project πŸ’š

- Become a Sponsor on GitHub
- One-time donation via PayPal

<!--sponsors start-->

<h4 align="center">Gold Sponsors</h4>
<p align="center">
<a href="https://www.coderabbit.ai/?utm_source=vuerouter&utm_medium=sponsor" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/coderabbitai-dark.svg" media="(prefers-color-scheme: dark)" height="72px" alt="CodeRabbit" />
<img src="https://posva-sponsors.pages.dev/logos/coderabbitai-light.svg" height="72px" alt="CodeRabbit" />
</picture>
</a>
</p>

<h4 align="center">Silver Sponsors</h4>
<p align="center">
<a href="https://www.vuemastery.com/" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/vuemastery-dark.png" media="(prefers-color-scheme: dark)" height="42px" alt="VueMastery" />
<img src="https://posva-sponsors.pages.dev/logos/vuemastery-light.svg" height="42px" alt="VueMastery" />
</picture>
</a>
<a href="https://www.controla.ai/?utm_source=posva" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/controla-dark.png" media="(prefers-color-scheme: dark)" height="42px" alt="Controla" />
<img src="https://posva-sponsors.pages.dev/logos/controla-light.png" height="42px" alt="Controla" />
</picture>
</a>
<a href="https://route4me.com" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/route4me.png" media="(prefers-color-scheme: dark)" height="42px" alt="Route Optimizer and Route Planner Software" />
<img src="https://posva-sponsors.pages.dev/logos/route4me.png" height="42px" alt="Route Optimizer and Route Planner Software" />
</picture>
</a>
<a href="https://jobs.sendcloud.com" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/sendcloud-dark.svg" media="(prefers-color-scheme: dark)" height="42px" alt="SendCloud" />
<img src="https://posva-sponsors.pages.dev/logos/sendcloud-light.svg" height="42px" alt="SendCloud" />
</picture>
</a>
</p>

<h4 align="center">Bronze Sponsors</h4>
<p align="center">
<a href="https://stormier.ninja" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://avatars.githubusercontent.com/u/2486424" media="(prefers-color-scheme: dark)" height="26px" alt="Stanislas Ormières" />
<img src="https://avatars.githubusercontent.com/u/2486424" height="26px" alt="Stanislas Ormières" />
</picture>
</a>
<a href="https://www.rtvision.com/" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://avatars.githubusercontent.com/u/8292810" media="(prefers-color-scheme: dark)" height="26px" alt="RTVision" />
<img src="https://avatars.githubusercontent.com/u/8292810" height="26px" alt="RTVision" />
</picture>
</a>
<a href="https://storyblok.com" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/storyblok.png" media="(prefers-color-scheme: dark)" height="26px" alt="Storyblok" />
<img src="https://posva-sponsors.pages.dev/logos/storyblok.png" height="26px" alt="Storyblok" />
</picture>
</a>
</p>

<!--sponsors end-->
<!--sponsors end-->

---

FAQ

A few notes about the project and possible questions:

Q: _Is Pinia the successor of Vuex?_

A: Yes

Q: _What about dynamic modules?_

A: Dynamic modules are not type safe, so instead we allow creating different stores that can be imported anywhere

Installation

bash

or pnpm or yarn


npm install pinia

Usage

Install the plugin

Create a pinia (the root store) and pass it to app:

js
// Vue 3
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

For more detailed instructions, including Nuxt configuration, check the Documentation.

Create a Store

You can create as many stores as you want, and they should each exist in different files:

ts
import { defineStore } from 'pinia'

// main is the name of the store. It is unique across your application
// and will appear in devtools
export const useMainStore = defineStore('main', {
// a function that returns a fresh state
state: () => ({
counter: 0,
name: 'Eduardo',
}),
// optional getters
getters: {
// getters receive the state as first parameter
doubleCounter: (state) => state.counter * 2,
// use getters in other getters
doubleCounterPlusOne(): number {
return this.doubleCounter + 1
},
},
// optional actions
actions: {
reset() {
// this is the store instance
this.counter = 0
},
},
})

defineStore returns a function that has to be called to get access to the store:

ts
import { useMainStore } from '@/stores/main'
import { storeToRefs } from 'pinia'

export default defineComponent({
setup() {
const main = useMainStore()

// extract specific store properties
const { counter, doubleCounter } = storeToRefs(main)

return {
// gives access to the whole store in the template
main,
// gives access only to specific state or getter
counter,
doubleCounter,
}
},
})

Documentation

To learn more about Pinia, check its documentation.

License

MIT