In a Vue 3 app with Pinia 4, what do createPinia(), app.use(pinia) and defineStore('cart', …) each do before a header badge can call useCartStore()?
answer
- root instance, installed once
- a definition is not an instance
- built lazily on first call
- one instance per id per pinia
- devtools-api peer since v4
basics
~20 screatePinia() builds the root container, app.use(pinia) installs it so components can find it, and defineStore('cart', …) only returns a useCartStore function; the store is created on its first call and then shared by every component.
solid answer
~40 s`createPinia()` creates the root `pinia` object: it holds the state of every store in `pinia.state` plus a registry of live stores keyed by id. `app.use(pinia)` runs its `install`, which provides it to the component tree and makes it the active pinia. `defineStore('cart', options | setup)` creates nothing yet: it returns a `useCartStore()` function. The first call, from the header badge's `<script setup>`, builds the store and registers it under `'cart'`; every later call, on the checkout page too, returns that same reactive object, so both screens show one cart. Name the function `use…Store`, keep one store per file, and in Pinia 4 install `@vue/devtools-api` next to `pinia`, because it is now a required peer dependency.
code
ts · 10 lines// main.ts
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')go deeper
Recall the order: createPinia, app.use before mount, then defineStore with a unique id and a use...Store call inside script setup. Say clearly that the store is shared, not per component.
Explain that defineStore only returns a function, that the store is built lazily on the first call and cached by id in the pinia, and what the dev error means when a store is used before app.use.
Point out the silent sharing when two definitions reuse an id, why one store per file helps code splitting and tooling, and that Pinia 4 needs @vue/devtools-api installed as a peer.
Frame the pinia instance as the unit of isolation: stores are cached per pinia, not per module, so whoever owns the pinia's lifetime owns the lifetime of every store in it.
## The three pieces and when each runs A Pinia setup has a few moving parts, and a common interview slip is to blur them. Only one call actually creates a store. | Call | What it produces | When it runs | |---|---|---| | `createPinia()` | the root `pinia` object: the state tree of every store plus a registry of live stores | once, in `main.ts` | | `app.use(pinia)` | nothing new; it installs the pinia into the app | once, before `app.mount()` | | `defineStore('cart', …)` | a `useCartStore` function, the **store definition** | when the module is imported | | `useCartStore()` | the store itself on the first call, the same instance afterwards | inside a component's `setup` | ## What createPinia() and app.use(pinia) do `createPinia()` returns the **root store**, usually just called *the pinia*. It holds: - `pinia.state`, a `ref` with one entry per store id: the whole application state in one tree, which is what devtools shows and what server rendering serialises; - an internal map of the stores already created, keyed by id; - an effect scope that owns every store's watchers and computeds. `app.use(pinia)` calls the pinia's `install` method. That method provides the pinia to the component tree, sets `app.config.globalProperties.$pinia`, marks this pinia as the **active** one so later `useStore()` calls can find it, and on the client registers the devtools integration. How `app.use()` invokes an `install` method is Vue's plugin contract, not Pinia's. ## defineStore() returns a function, not a store `defineStore()` takes a **unique id** as its first argument and either an options object or a setup function as its second. The id connects the store to devtools and names its slot in `pinia.state`. The return value is a function, by convention named `use` + name + `Store`: - it carries its id as `useCartStore.$id`; - the first call looks up the active pinia, builds the store and registers it under `'cart'`; - every later call, from the header badge, the checkout page or another store, returns **that same reactive object**. Because nothing happens until the first call, a store that is defined but never used never creates state or runs its setup; Pinia even annotates `defineStore` as side-effect free so bundlers can drop unused definitions. The docs recommend **one store per file**, so bundlers can code-split stores and TypeScript can infer each one cleanly. ```ts // stores/cart.ts import { ref, computed } from 'vue' import { defineStore } from 'pinia' export const useCartStore = defineStore('cart', () => { const items = ref<{ sku: string; qty: number }[]>([]) const itemCount = computed(() => items.value.reduce((n, i) => n + i.qty, 0)) function addItem(sku: string) { items.value.push({ sku, qty: 1 }) } return { items, itemCount, addItem } }) ``` ## Using the store from two screens The header badge and the checkout page each call `useCartStore()` in `<script setup>`. They receive the same instance, so an item added on the checkout page shows up in the badge immediately: - the badge only reads `cart.itemCount` in its template; - the checkout page calls `cart.addItem(sku)` from a button handler; - both re-render from the same state, because the pinia holds exactly one `'cart'`. Neither component imports the other or passes props for the cart; the shared pinia is the only link between them. The store is wrapped in `reactive()`, so you read `cart.itemCount`, not `cart.itemCount.value`, even though it was declared with `computed()`. ## Installing Pinia 4 1. Install `pinia` **and** `@vue/devtools-api`: since Pinia 4.0 the devtools API is a required peer dependency you add yourself, and the package ships as ESM only. 2. Call `createPinia()` and `app.use(pinia)` before `app.mount()`. 3. Define each store in its own file with `defineStore(id, …)`. 4. Call the `use…Store()` function inside `setup`. ## Mistakes interviewers probe - **Using a store before `app.use(pinia)`.** With no active pinia, a development build throws an error asking whether you used a store before calling `app.use(pinia)`, and warns that it will fail in production. Store use outside components is a subject of its own. - **Reusing an id.** Two definitions with the id `'cart'` do not conflict loudly: whichever `useStore` function runs first creates the store, and the other silently returns that instance. - **The old object form.** `defineStore({ id: 'cart', … })` was removed in Pinia 3; the id is always the first argument now. - **Expecting per-component copies.** A store is one instance per pinia; state that belongs to one component instance stays in that component.
- What happens if two files both call defineStore('cart', …) with different definitions?Pinia keys live stores by id inside a pinia. Whichever `useStore` function runs first creates the store under `'cart'`; the other finds that id already registered and returns the same instance, built from the first definition. Nothing warns you, so the second definition's state and actions simply never exist. Ids must be unique across the app, which is one reason to keep one store per file named after its id.
- Why does calling useCartStore() in main.ts before app.use(pinia) fail?`useCartStore()` needs an active pinia: inside a component it injects the one the app provides, otherwise it falls back to the pinia that `app.use(pinia)` made active. Before that there is none, so a development build throws an error asking whether you used a store before calling `app.use(pinia)`, and warns that it will fail in production. Install the pinia first, then use stores.
saying these in an interview costs you the question
- defineStore creates the store instance as soon as its module is imported.
- Each component that calls useCartStore() gets its own copy of the cart.
- app.use(pinia) creates every store defined in the app up front.
- Pinia 4 still accepts defineStore({ id: 'cart', ... }) with the id inside the object.
- Only pinia needs installing in Pinia 4; the devtools package is bundled.