How to debug Vue with DevTools

Debugging Vue applications with Vue DevTools provides powerful inspection of components, state, events, routing, and performance profiling. As the creator of CoreUI with over 12 years of Vue.js experience since 2014, I’ve used Vue DevTools extensively for debugging complex applications. Vue DevTools browser extension integrates with Chrome and Firefox, offering real-time component inspection and time-travel debugging. This approach makes debugging Vue applications significantly faster with visual component hierarchy and reactive data tracking.

Install Vue DevTools browser extension to inspect component state, debug reactivity, and profile performance in Vue applications.

Installing Vue DevTools:

# Chrome Web Store
# Search for "Vue.js devtools" and install

# Firefox Add-ons
# Search for "Vue.js devtools" and install

# Standalone Electron app
npm install -g @vue/devtools
vue-devtools

Enable in development:

// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// Enable DevTools in development
if (import.meta.env.MODE === 'development') {
  app.config.performance = true
  app.config.devtools = true
}

app.mount('#app')

Component inspection:

<script setup>
import { ref, computed, watch } from 'vue'

// All these are visible in DevTools
const count = ref(0)
const message = ref('Hello')

const doubled = computed(() => count.value * 2)

watch(count, (newVal, oldVal) => {
  console.log(`Count changed from ${oldVal} to ${newVal}`)
})

const increment = () => {
  count.value++
}

// Component name for DevTools (useful for production builds)
defineOptions({
  name: 'CounterComponent'
})
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Doubled: {{ doubled }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

DevTools features:

<script setup>
import { ref, reactive, provide, inject } from 'vue'

// 1. Component Tree - View component hierarchy
// Click components to inspect props, data, computed

// 2. Component State - Inspect reactive state
const state = reactive({
  user: {
    name: 'John',
    email: '[email protected]'
  },
  settings: {
    theme: 'dark',
    notifications: true
  }
})

// 3. Props inspection
const props = defineProps({
  title: String,
  count: Number
})

// 4. Computed properties - See cached values
const fullName = computed(() => {
  return `${state.user.name} (${state.user.email})`
})

// 5. Provide/Inject - Track dependency injection
provide('theme', state.settings.theme)
const theme = inject('theme')

// 6. Edit state in DevTools - Modify values live
const editable = ref('Edit me in DevTools')

// 7. Timeline - Track events, mutations, component updates
const emit = defineEmits(['update', 'delete'])

const handleUpdate = () => {
  emit('update', { id: 1, name: 'Updated' })
}
</script>

Performance profiling:

<script setup>
import { ref, onMounted, onUpdated } from 'vue'

// Enable performance tracking
onMounted(() => {
  console.log('Component mounted')
})

onUpdated(() => {
  console.log('Component updated')
})

// DevTools Performance Tab shows:
// - Component render time
// - Lifecycle hook timing
// - Update frequency
// - Memory usage

const items = ref(Array.from({ length: 1000 }, (_, i) => ({
  id: i,
  name: `Item ${i}`
})))

// Use DevTools to profile this expensive operation
const sortItems = () => {
  performance.mark('sort-start')
  items.value = [...items.value].sort((a, b) =>
    a.name.localeCompare(b.name)
  )
  performance.mark('sort-end')
  performance.measure('sort', 'sort-start', 'sort-end')
}
</script>

Routing inspection:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('./views/Home.vue')
    },
    {
      path: '/users/:id',
      name: 'UserProfile',
      component: () => import('./views/UserProfile.vue'),
      meta: { requiresAuth: true }
    }
  ]
})

// DevTools Router Tab shows:
// - Current route
// - Route params
// - Route meta
// - Navigation history
// - Route guards execution

export default router

Vuex/Pinia store inspection:

// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    user: null,
    isAuthenticated: false,
    preferences: {
      theme: 'light',
      language: 'en'
    }
  }),

  getters: {
    fullName: (state) => {
      return state.user ? `${state.user.firstName} ${state.user.lastName}` : ''
    }
  },

  actions: {
    setUser(user) {
      this.user = user
      this.isAuthenticated = true
      // DevTools shows this mutation in timeline
    },

    updatePreferences(preferences) {
      this.preferences = { ...this.preferences, ...preferences }
    }
  }
})

// DevTools Pinia Tab shows:
// - All stores
// - Current state
// - Getters values
// - Actions history
// - Time-travel debugging

Custom DevTools plugin:

// devtools-plugin.js
export function setupDevTools(app) {
  if (import.meta.env.MODE === 'development' && window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
    app.config.globalProperties.$devtools = {
      log: (message, data) => {
        console.log('[DevTools]', message, data)
        // Send custom data to DevTools
        window.__VUE_DEVTOOLS_GLOBAL_HOOK__.emit('custom-log', {
          message,
          data,
          timestamp: Date.now()
        })
      }
    }
  }
}

// Usage in component
const devtools = inject('$devtools')
devtools?.log('User action', { action: 'click', target: 'button' })

Debugging tips:

<script setup>
import { ref, watchEffect } from 'vue'

const count = ref(0)

// 1. Use DevTools breakpoints
// Click "Bug" icon in DevTools to pause on component updates

// 2. Inspect reactive dependencies
watchEffect(() => {
  console.log('Count changed:', count.value)
  // DevTools shows what triggered this watcher
})

// 3. Edit state live
// Change values in DevTools to test different states

// 4. Time-travel debugging
// Use timeline to replay component state changes

// 5. Export state
// Right-click component in DevTools > "Export state to console"

// 6. Force update
// Right-click component > "Force update" to trigger re-render

const debugHelper = () => {
  // DevTools can intercept and inspect this
  console.log('Current state:', count.value)
}
</script>

Best Practice Note

Install Vue DevTools from official Chrome or Firefox stores. Enable devtools in development mode only. Use component tree to understand component hierarchy. Inspect reactive state to debug reactivity issues. Use timeline to track events and mutations. Profile performance to identify slow components. Use time-travel debugging to replay state changes. Export component state for testing. This is how we debug CoreUI Vue applications—Vue DevTools for real-time component inspection, performance profiling, and time-travel debugging making development significantly faster and more efficient.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author