Composing Stores and Cross-Store Access
Using one store inside another, store composition patterns, avoiding circular dependencies.
Composing Stores and Cross-Store Access is a free Vue Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Stores Can Use Other Stores
Real apps have multiple stores that need each other. A cart store may need the auth store to know the current user. Pinia makes cross-store access straightforward.
Calling a Store Inside an Action
Inside an action, simply call the other store composable. Because actions run after Pinia is active, this is safe.
import { useAuthStore } from './auth'
export const useCartStore = defineStore('cart', {
state: () => ({ items: [] }),
actions: {
checkout() {
const auth = useAuthStore()
if (!auth.isLoggedIn) return
// proceed with auth.userId
}
}
})The Setup Store Syntax
Besides the options object, defineStore accepts a setup function. It looks like a component setup: declare refs and computeds, then return them.
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
return { count }
})State as refs
In a setup store, every ref or reactive you return becomes state. Use ref for primitives and reactive for objects.
export const useUserStore = defineStore('user', () => {
const name = ref('Coddy')
const profile = reactive({ age: 30 })
return { name, profile }
})Getters as computed
A returned computed acts as a getter. It is cached and reactive, just like option-store getters.
export const useCounterStore = defineStore('counter', () => {
const count = ref(2)
const doubled = computed(() => count.value * 2)
return { count, doubled }
})Actions as Functions
A returned function is an action. It can read and write the refs directly using .value.
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() { count.value++ }
return { count, increment }
})Returning refs and computed
The key rule for setup stores: return everything you want exposed. Anything not returned stays private to the store.
export const useStore = defineStore('s', () => {
const visible = ref(0)
const secret = ref('hidden') // not returned -> private
return { visible }
})Cross-Store in a Setup Store
In a setup store you can call another store at the top level and use it in computeds or actions.
export const useCartStore = defineStore('cart', () => {
const auth = useAuthStore()
const canCheckout = computed(() => auth.isLoggedIn)
return { canCheckout }
})Avoiding Circular Dependencies
If store A imports store B and B imports A, you can hit a circular dependency. Avoid calling the other store at module top-level; instead call it inside the action or getter where it is needed.
// Risky: top-level use in both directions
// Safe: call useOtherStore() lazily inside the action
actions: {
doWork() {
const other = useOtherStore() // resolved at call time
}
}Why Lazy Calls Help
Calling the store composable inside a function defers resolution until runtime, after all modules have loaded. This breaks the import cycle that crashes at module evaluation time.
Option vs Setup Stores
Both styles are equal in power. Choose option stores for a familiar, declarative shape; choose setup stores when you want full Composition API flexibility like watchers or composables inside the store.
Quick Check
Test your understanding of composing stores.
Recap
You learned to compose stores:
- Call another store composable inside an action for cross-store access.
- Setup stores use a function: refs are state, computed are getters, functions are actions.
- Return everything you want exposed.
- Call stores lazily inside functions to avoid circular dependencies.
Frequently asked questions
Is the “Composing Stores and Cross-Store Access” lesson free?
Yes — the full text of “Composing Stores and Cross-Store Access” is free to read here on the web, and the Vue Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Vue Academy course, upgrade to CoddyKit PRO.
What will I learn in “Composing Stores and Cross-Store Access”?
Using one store inside another, store composition patterns, avoiding circular dependencies. You practise Vue Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Vue Academy?
No prior experience is required. Vue Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Composing Stores and Cross-Store Access” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Vue Academy lesson?
Yes. Every Vue Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Pinia vs Vuex: Why the Switch
- defineStore: State, Getters, Actions
- Composing Stores and Cross-Store Access
- Pinia Persistence and Devtools