How to Use Vuex Store

How to Use Vuex Store Vuex is the official state management pattern and library for Vue.js applications. It serves as a centralized store for all the components in an application, enabling predictable state changes and seamless data sharing across component boundaries. As Vue applications grow in complexity—especially those with deeply nested component hierarchies or multiple views sharing the sam

Oct 30, 2025 - 13:25
Oct 30, 2025 - 13:25
 0

How to Use Vuex Store

Vuex is the official state management pattern and library for Vue.js applications. It serves as a centralized store for all the components in an application, enabling predictable state changes and seamless data sharing across component boundaries. As Vue applications grow in complexityespecially those with deeply nested component hierarchies or multiple views sharing the same datamanaging state through props and events becomes unwieldy and error-prone. Vuex solves this by providing a single source of truth for application state, making it easier to debug, test, and maintain large-scale applications.

At its core, Vuex is built on the principles of flux architecture, combining concepts from Redux and Reacts unidirectional data flow. It enforces a strict structure: state is read-only, changes are made through explicit mutations, and side effects are handled via actions. This disciplined approach ensures that every state change is traceable, logged, and reversiblecritical features for modern web development.

Whether youre building a dashboard with real-time data, an e-commerce platform with cart and user authentication, or a multi-step form with shared validation logic, Vuex provides the infrastructure to manage complexity without sacrificing performance or readability. In this comprehensive guide, well walk you through everything you need to know to effectively use Vuex Storefrom initial setup to advanced patterns and real-world implementation.

Step-by-Step Guide

1. Installing Vuex

Before you can use Vuex, you must install it in your Vue project. If youre using Vue 3, youll need Vuex 4, which is compatible with Vue 3s Composition API. For Vue 2 projects, use Vuex 3.

To install Vuex via npm, run:

npm install vuex@4

Or if you're using yarn:

yarn add vuex@4

If you're using Vue CLI or Vite, the package will be automatically registered when you import it into your main application file.

2. Creating the Store

The Vuex store is a JavaScript module that exports a configured instance of the store. Create a new file in your projecttypically under src/store/index.jsand define your initial store structure.

Heres a minimal example:

import { createStore } from 'vuex'

export default createStore({

state: {

count: 0

},

mutations: {

increment(state) {

state.count++

}

},

actions: {

incrementAsync({ commit }) {

setTimeout(() => {

commit('increment')

}, 1000)

}

},

getters: {

doubleCount: state => state.count * 2

}

})

Lets break this down:

  • state: Contains the applications data. This is the single source of truth.
  • mutations: Synchronous functions that modify the state. They are the only way to directly change state.
  • actions: Asynchronous functions that commit mutations. Used for handling side effects like API calls.
  • getters: Computed properties for the state. Useful for filtering, sorting, or deriving new values from state.

3. Registering the Store in Your App

Once the store is created, you need to register it with your Vue application. In your main.js file (or main.ts if using TypeScript), import the store and pass it to the Vue app instance.

import { createApp } from 'vue'

import App from './App.vue'

import store from './store'

const app = createApp(App)

app.use(store) app.mount('

app')

After this step, the store is available to all components in your application via the $store property.

4. Accessing State in Components

There are multiple ways to access state from within a Vue component. The most straightforward is using this.$store.state in Options API components.

<template>

<div>

<p>Count: {{ $store.state.count }}</p>

<p>Double Count: {{ $store.getters.doubleCount }}</p>

<button @click="$store.commit('increment')">Increment</button>

<button @click="$store.dispatch('incrementAsync')">Increment Async</button>

</div>

</template>

While this works, its not scalable or readable in larger components. A better approach is to use the mapState, mapGetters, mapMutations, and mapActions helpers.

<template>

<div>

<p>Count: {{ count }}</p>

<p>Double Count: {{ doubleCount }}</p>

<button @click="increment">Increment</button>

<button @click="incrementAsync">Increment Async</button>

</div>

</template>

<script>

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {

computed: {

...mapState(['count']),

...mapGetters(['doubleCount'])

},

methods: {

...mapMutations(['increment']),

...mapActions(['incrementAsync'])

}

}

</script>

This approach improves code clarity and reduces boilerplate. You can also map specific properties with aliases:

...mapState({

counter: 'count',

amount: state => state.count * 2

})

5. Using the Composition API with Vuex

If youre using Vue 3s Composition API, you can leverage the useStore composable from Vuex to access the store inside the setup() function.

<template>

<div>

<p>Count: {{ count }}</p>

<p>Double Count: {{ doubleCount }}</p>

<button @click="increment">Increment</button>

<button @click="incrementAsync">Increment Async</button>

</div>

</template>

<script>

import { computed } from 'vue'

import { useStore } from 'vuex'

export default {

setup() {

const store = useStore()

const count = computed(() => store.state.count)

const doubleCount = computed(() => store.getters.doubleCount)

const increment = () => store.commit('increment')

const incrementAsync = () => store.dispatch('incrementAsync')

return {

count,

doubleCount,

increment,

incrementAsync

}

}

}

</script>

This pattern is especially useful when building reusable logic in custom composables.

6. Using Namespaces for Modular Stores

As your application grows, the store file can become bloated. To maintain organization, Vuex supports modules. Each module can have its own state, mutations, actions, and getters.

Create a module file, for example src/store/modules/user.js:

const userModule = {

namespaced: true,

state: {

name: 'John Doe',

isLoggedIn: false

},

mutations: {

login(state) {

state.isLoggedIn = true

},

logout(state) {

state.isLoggedIn = false

}

},

actions: {

loginUser({ commit }) {

// Simulate API call

setTimeout(() => {

commit('login')

}, 1000)

},

logoutUser({ commit }) {

setTimeout(() => {

commit('logout')

}, 500)

}

},

getters: {

fullName: state => state.name.toUpperCase()

}

}

export default userModule

Then register it in your main store:

import { createStore } from 'vuex'

import userModule from './modules/user'

export default createStore({

modules: {

user: userModule

}

})

Now, to access namespaced state, you must prefix the path:

// In components

this.$store.state.user.name

this.$store.getters['user/fullName']

this.$store.commit('user/login')

this.$store.dispatch('user/loginUser')

Or use the helpers with namespace:

...mapState('user', ['name']),

...mapGetters('user', ['fullName']),

...mapMutations('user', ['login', 'logout']),

...mapActions('user', ['loginUser', 'logoutUser'])

7. Persisting State with Plugins

By default, Vuex state is lost when the page is refreshed. To persist state across sessions (e.g., user preferences, login tokens), use a plugin like vuex-persistedstate.

Install it:

npm install vuex-persistedstate

Then import and use it in your store:

import { createStore } from 'vuex'

import createPersistedState from 'vuex-persistedstate'

export default createStore({

plugins: [createPersistedState()],

state: {

count: 0,

user: null

},

// ... rest of store

})

This will automatically save state to localStorage. You can customize the storage key, paths, or use sessionStorage:

createPersistedState({

key: 'my-app',

paths: ['user'], // Only persist user state

storage: window.sessionStorage

})

Best Practices

1. Keep State Minimal

Only store data in Vuex that is genuinely shared across multiple components. Avoid putting every piece of UI state (like a modals open/closed status) into the store unless its required globally. Local component state with ref() or reactive() is often more appropriate.

2. Use Mutations for Synchronous Changes

Always use mutations to change state. Mutations must be synchronous to allow for time-travel debugging and accurate state snapshots. If you need to perform asynchronous operations (like API calls), use actions to commit mutations after the async task completes.

3. Name Mutations and Actions Clearly

Use descriptive, consistent names. Avoid abbreviations. For example:

  • Good: setUser, fetchProducts, removeCartItem
  • Avoid: updUsr, getProds, rmItem

Use PascalCase or camelCase consistently across your project.

4. Avoid Direct State Mutation

Never mutate state directly from components. Always go through mutations. This ensures all state changes are tracked by Vue DevTools and enables debugging tools to function correctly.

5. Use Getters for Computed Logic

Instead of computing derived values in templates or methods, use getters. They are cached based on their dependencies and only recompute when their inputs changeimproving performance.

getters: {

activeProducts: state => state.products.filter(p => p.isActive),

productCount: state => state.products.length

}

6. Structure Modules Logically

Organize your store into feature-based modules: auth, cart, products, userProfile, etc. This makes the codebase easier to navigate and test.

Each module should be self-contained and have clear boundaries. Avoid circular dependencies between modules.

7. Use TypeScript for Type Safety

If youre using Vue 3 with TypeScript, define types for your state, mutations, actions, and getters. This prevents runtime errors and improves developer experience.

interface State {

count: number

user: User | null

}

const store = createStore({

state: {

count: 0,

user: null

},

mutations: {

increment(state) {

state.count++

}

}

})

8. Test Your Store

Write unit tests for your store modules. Since Vuex logic is pure JavaScript, its easy to test without a DOM.

import { createStore } from 'vuex'

import userModule from '@/store/modules/user'

describe('userModule', () => {

let store

beforeEach(() => {

store = createStore({

modules: {

user: userModule

}

})

})

test('logs in user', () => {

store.commit('user/login')

expect(store.state.user.isLoggedIn).toBe(true)

})

test('fetches user data', async () => {

await store.dispatch('user/loginUser')

expect(store.state.user.isLoggedIn).toBe(true)

})

})

9. Avoid Overusing Vuex

Dont use Vuex as a replacement for local component state. If a piece of data is only used within one component or a small parent-child tree, keep it local. Vuex adds overhead and complexityonly use it when you need global state management.

10. Use Vue DevTools

Install the Vue DevTools browser extension. It provides a visual interface to inspect state, track mutations, and even time-travel through state history. This is indispensable for debugging Vuex applications.

Tools and Resources

1. Vue DevTools

The official Vue DevTools extension for Chrome and Firefox is essential for debugging Vuex. It displays the entire state tree, logs every mutation, and allows you to rewind to previous states. This is especially helpful when tracking down unintended state changes.

Download: https://devtools.vuejs.org/

2. Vuex-PersistedState

As mentioned earlier, this plugin automatically persists your Vuex store to localStorage or sessionStorage. Its lightweight and highly configurable.

GitHub: https://github.com/robinvdvleuten/vuex-persistedstate

3. Pinia (Alternative to Vuex)

While Vuex remains the official state management solution, Pinia is the newer, more modern alternative recommended by the Vue team for Vue 3 applications. Its simpler, has better TypeScript support, and eliminates the need for mutations and actions in many cases.

Learn more: https://pinia.vuejs.org/

4. Vuex-ORM

If your application interacts heavily with REST APIs and needs to manage relational data (e.g., users with posts, comments), Vuex-ORM provides an ORM-like layer over Vuex. It helps normalize data and manage relationships.

Website: https://vuex-orm.github.io/vuex-orm/

5. Vue CLI and Vite

Use Vue CLI or Vite to scaffold your project with Vuex preconfigured. Both tools offer templates that include Vuex setup, saving you time on boilerplate.

6. Official Vuex Documentation

The most authoritative resource for learning Vuex is the official documentation. It includes detailed guides, API references, and examples.

Documentation: https://vuex.vuejs.org/

7. Vue Mastery and Udemy Courses

For visual learners, Vue Mastery offers excellent courses on Vuex and state management. Udemy also has comprehensive tutorials with real-world projects.

8. GitHub Repositories

Study open-source Vue applications on GitHub to see how Vuex is used in production. Popular examples include:

Real Examples

Example 1: User Authentication System

Many applications require authentication. Heres how to structure a simple auth system using Vuex.

store/modules/auth.js

const authModule = {

namespaced: true,

state: {

token: localStorage.getItem('authToken') || null,

user: JSON.parse(localStorage.getItem('user')) || null,

loading: false,

error: null

},

mutations: {

SET_TOKEN(state, token) {

state.token = token

localStorage.setItem('authToken', token)

},

SET_USER(state, user) {

state.user = user

localStorage.setItem('user', JSON.stringify(user))

},

CLEAR_AUTH(state) {

state.token = null

state.user = null

localStorage.removeItem('authToken')

localStorage.removeItem('user')

},

SET_LOADING(state, loading) {

state.loading = loading

},

SET_ERROR(state, error) {

state.error = error

}

},

actions: {

async login({ commit }, credentials) {

commit('SET_LOADING', true)

commit('SET_ERROR', null)

try {

const response = await fetch('/api/login', {

method: 'POST',

headers: { 'Content-Type': 'application/json' },

body: JSON.stringify(credentials)

})

const data = await response.json()

if (response.ok) {

commit('SET_TOKEN', data.token)

commit('SET_USER', data.user)

} else {

commit('SET_ERROR', data.message || 'Login failed')

}

} catch (error) {

commit('SET_ERROR', 'Network error')

} finally {

commit('SET_LOADING', false)

}

},

logout({ commit }) {

commit('CLEAR_AUTH')

}

},

getters: {

isAuthenticated: state => !!state.token,

currentUser: state => state.user

}

}

export default authModule

Component Usage

<template>

<div>

<div v-if="$store.getters['auth/isAuthenticated']">

<p>Welcome, {{ $store.getters['auth/currentUser'].name }}!</p>

<button @click="$store.dispatch('auth/logout')">Logout</button>

</div>

<div v-else>

<button @click="login">Login</button>

<p v-if="$store.state.auth.error">{{ $store.state.auth.error }}</p>

</div>

</div>

</template>

<script>

import { mapGetters, mapActions } from 'vuex'

export default {

computed: {

...mapGetters('auth', ['isAuthenticated', 'currentUser'])

},

methods: {

...mapActions('auth', ['login', 'logout']),

login() {

this.login({ email: 'test@example.com', password: 'password' })

}

}

}

</script>

Example 2: Shopping Cart

A cart system requires adding/removing items, calculating totals, and persisting state.

store/modules/cart.js

const cartModule = {

namespaced: true,

state: {

items: []

},

mutations: {

ADD_ITEM(state, product) {

const existing = state.items.find(item => item.id === product.id)

if (existing) {

existing.quantity++

} else {

state.items.push({ ...product, quantity: 1 })

}

},

REMOVE_ITEM(state, productId) {

state.items = state.items.filter(item => item.id !== productId)

},

UPDATE_QUANTITY(state, { id, quantity }) {

const item = state.items.find(item => item.id === id)

if (item) {

item.quantity = quantity < 1 ? 1 : quantity

}

},

CLEAR_CART(state) {

state.items = []

}

},

actions: {

addToCart({ commit }, product) {

commit('ADD_ITEM', product)

},

removeFromCart({ commit }, productId) {

commit('REMOVE_ITEM', productId)

},

updateQuantity({ commit }, payload) {

commit('UPDATE_QUANTITY', payload)

},

clearCart({ commit }) {

commit('CLEAR_CART')

}

},

getters: {

itemCount: state => state.items.reduce((sum, item) => sum + item.quantity, 0),

totalAmount: state => state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),

cartItems: state => state.items

}

}

export default cartModule

Component Usage

<template>

<div>

<h3>Cart ({ $store.getters['cart/itemCount'] } items) - ${{ $store.getters['cart/totalAmount'] }}</h3>

<ul>

<li v-for="item in $store.getters['cart/cartItems']" :key="item.id">

{{ item.name }} x {{ item.quantity }} - ${{ item.price * item.quantity }}

<button @click="$store.dispatch('cart/updateQuantity', { id: item.id, quantity: item.quantity - 1 })">-</button>

<button @click="$store.dispatch('cart/updateQuantity', { id: item.id, quantity: item.quantity + 1 })">+</button>

<button @click="$store.dispatch('cart/removeFromCart', item.id)">Remove</button>

</li>

</ul>

<button @click="$store.dispatch('cart/clearCart')">Clear Cart</button>

</div>

</template>

Example 3: Global Loading Indicator

Use Vuex to manage a global loading state that affects multiple components.

store/modules/loading.js

const loadingModule = {

namespaced: true,

state: {

active: false,

count: 0

},

mutations: {

START_LOADING(state) {

state.count++

state.active = true

},

STOP_LOADING(state) {

state.count--

if (state.count === 0) {

state.active = false

}

}

},

actions: {

start({ commit }) {

commit('START_LOADING')

},

stop({ commit }) {

commit('STOP_LOADING')

}

},

getters: {

isLoading: state => state.active

}

}

export default loadingModule

Use this in API services:

export async function fetchProducts() {

store.dispatch('loading/start')

try {

const response = await fetch('/api/products')

return await response.json()

} finally {

store.dispatch('loading/stop')

}

}

And display a spinner globally:

<template>

<div>

<div v-if="$store.getters['loading/isLoading']">

<div class="spinner">Loading...</div>

</div>

<!-- other content -->

</div>

</template>

FAQs

Is Vuex still relevant with Vue 3?

Yes, Vuex is still fully supported and maintained. However, the Vue team recommends Pinia for new Vue 3 projects due to its simpler API and better TypeScript integration. Vuex remains the standard for legacy applications and teams already invested in its ecosystem.

Can I use Vuex without Vue CLI?

Absolutely. Vuex works with any build tool, including Vite, Webpack, or even plain HTML with CDN scripts. Just ensure you import the correct version and register it with your Vue app instance.

Do I need to use modules in Vuex?

No, modules are optional. For small applications, a single store file is acceptable. However, as your application scales, modules become essential for maintainability and code organization.

How do I reset Vuex state on logout?

Define a root mutation that resets all state to its initial values. You can also use a plugin like vuex-reset or manually dispatch a reset action in your auth module.

Can I use Vuex with server-side rendering (SSR)?

Yes, but you must create a new store instance for each request to avoid cross-user state leakage. Vuex provides guidance for SSR in its documentation.

Whats the difference between mutations and actions?

Mutations are synchronous functions that directly modify state. Actions are asynchronous and can perform side effects (like API calls) before committing mutations. Actions can also commit multiple mutations and call other actions.

Can I have multiple stores in one application?

No, Vuex enforces a single store per application. However, you can use multiple modules within that store to logically separate concerns.

How does Vuex compare to Reacts Context API?

Vuex provides a more structured, predictable state management system with built-in devtools, time-travel debugging, and strict separation of concerns. React Context is simpler but lacks these features out of the box. Redux (the React equivalent of Vuex) offers similar structure to Vuex.

Does Vuex affect performance?

Minimal impact. Vuex uses Vues reactivity system efficiently. The overhead is negligible for most applications. The real performance gains come from using getters (computed properties) and avoiding unnecessary re-renders.

Can I use Vuex with Vue 2?

Yes. Use Vuex 3 for Vue 2 applications. The API is nearly identical to Vuex 4, with minor differences in module registration and the Composition API.

Conclusion

Vuex Store is a powerful tool for managing state in Vue.js applications. By centralizing your applications data, enforcing predictable state changes, and enabling seamless communication between components, Vuex reduces complexity and improves maintainability. Whether youre building a small single-page app or a large enterprise dashboard, understanding how to use Vuex effectively is a critical skill for any Vue developer.

In this guide, weve covered everything from installation and basic setup to advanced patterns like namespacing, persistence, and real-world use cases. Weve explored best practices to avoid common pitfalls and recommended tools to enhance your development workflow.

Remember: Vuex is not a silver bullet. Use it where it adds valuenot everywhere. Keep your state minimal, structure your modules logically, and always prioritize code clarity over cleverness.

As you continue to build Vue applications, revisit your state management strategy regularly. Consider migrating to Pinia for new projects, but dont underestimate the enduring power of Vuex in legacy and complex applications. With the principles outlined here, youre now equipped to build scalable, maintainable, and debuggable Vue applications with confidence.