Taking Pinia to production means going beyond syntax. This episode covers store architecture for team scale, conventions and documentation, dividing server state with Vue Query or Colada, and production quality: type-check, lint, test coverage, monitoring, and bundle size.

The code that runs on your laptop and the code that runs in production are two different worlds. In production, there's a team, monitoring, SLAs — and state management becomes part of that quality. Episode 21 brings all the lessons together into a production-ready architecture.
Episode 21 covers store architecture for team scale, conventions and documentation, dividing server state with Vue Query or Colada, and quality practices: type-check, lint, test coverage, monitoring, and bundle size.
In large teams, agreements are worth more than personal preferences. Common standards include:
use<Name>Store, verb actions, noun getters.// Every store satisfies:
// 1. One domain (auth, cart, ui)
// 2. State without data that can be recomputed
// 3. Getters for derived state
// 4. Actions for all mutations and side effectsThis simple discipline makes pull requests easy to review and onboarding new developers much faster. When the whole team uses the same framework, knowledge diffusion also improves: already-agreed decisions don't need to be re-discussed in every review. The only things left to debate are genuinely new ones — not how to name an action or where a piece of state should live.
A good store is briefly documented above its definition. This documentation lives alongside the code, so it always stays in sync with the implementation:
/**
* Store for the shopping cart.
* Uses the userStore for member discounts.
* Product server state is handled by useProductsQuery (Colada).
*/
export const useCartStore = defineStore('cart', () => {
// ...
})A single short block of documentation — purpose, dependencies, and the contract with server state — is enough to explain intent without maintaining a separate documentation file that easily goes stale.
Avoid documenting how internals work in comments; explain the reasoning and the store's scope of responsibility. For example, the comment above useCartStore mentions two important things: this store uses the userStore for discounts, and product data is handled by Colada, not here. Those two lines save another developer from guessing whether products may enter the cart state — the answer is no, and it's written explicitly.
If your team uses tools like JSDoc, this small agreement can be encoded in a template: a short title, one sentence on purpose, then a list of dependencies. Format consistency makes documentation readable without switching styles.
The division of responsibilities we built in episode 14 now becomes a team rule:
useProductsQuery() // server state: fetch, cache, invalidation
useCartStore() // client state: user interactionuseProductsQuery() from Colada or Vue Query handles fetching, caching, deduplication, and retry. Stores stay focused on state owned by the client. This split is what prevents stores from becoming uncontrolled dumping grounds for API data.
An easy-to-recognize signal: if a store holds the same fetch result as another page, or if a store action only forwards API calls without client logic, that state probably should be handled by a server-state library.
Quality is enforced by machines, not good intentions. Run this in CI:
bun run lint
bun run typecheck
bun run test --coverage
bun run buildbun run lint and bun run typecheck keep the code consistent and type-safe; tests with coverage focus on critical stores (auth, cart, checkout); bun run build ensures the entire compilation chain is clean. Production error monitoring catches the problems that slip past all of these.
The order of these gates is deliberate: lint catches syntax and style problems quickly, typecheck catches contracts between modules, tests verify store behavior on critical cases, and build ensures the entire compilation pipeline works end to end. When one gate fails in CI, the pull request must not be merged until the fix lands. A consistent machine like this is far more reliable than relying on each developer's memory.
Pinia is about 1 KB and supports tree-shaking — just import from pinia and the build tool drops unused code:
import { createPinia, defineStore, storeToRefs } from 'pinia'import { createPinia, defineStore, storeToRefs } from 'pinia' ensures only the symbols you use end up in the bundle. Monitor bundle size in CI with a bundle analyzer so new features don't silently inflate the bundle.
The rule of thumb is simple: every new import must pass the question "is this symbol actually used?". When the whole team resists importing an entire store just for one getter, the bundle stays lean naturally. Set an explicit threshold — for example, reject a PR when bundle size rises more than five percent — so this discussion happens in the machine, not in meeting rooms.
Warning
A type-check in production can protect against a whole class of bugs that are hard to catch in development. Make sure vue-tsc also runs on the production build.
Episode 21 summarizes the practices that take Pinia to production. You now have team architecture standards, documentation practices, the server/client state split, and quality gates: lint, type-check, coverage, monitoring, and bundle size.
Key takeaways:
In episode 22, the final episode, we'll discuss alternative ecosystems and final reflections — comparing Pinia with Vuex 4, manual composables, and signal-based stores, building a 2026 Vue state management decision framework, and recapping the journey of episodes 0-21 and the direction of Vue's evolution.