How to watch deep objects in Vue

Watching deeply nested objects is essential for Vue applications that need to react to changes in complex data structures. As the creator of CoreUI with over 11 years of Vue development experience since 2014, I’ve implemented deep watchers in countless form validation and state management scenarios. The most effective solution is to use the watch function with the deep option to monitor all nested property changes. This approach ensures reactivity for complex objects with multiple levels of nesting.

Use the deep option in watch to monitor nested object changes in Vue 3.

<template>
  <div>
    <h2>User Profile</h2>
    <input v-model='user.name' placeholder='Name' />
    <input v-model='user.email' placeholder='Email' />

    <h3>Address</h3>
    <input v-model='user.address.street' placeholder='Street' />
    <input v-model='user.address.city' placeholder='City' />
    <input v-model='user.address.zip' placeholder='Zip' />

    <p>Changes detected: {{ changeCount }}</p>
  </div>
</template>

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

export default {
  setup() {
    const user = ref({
      name: 'John Doe',
      email: '[email protected]',
      address: {
        street: '123 Main St',
        city: 'New York',
        zip: '10001'
      }
    })

    const changeCount = ref(0)

    // Watch with deep option
    watch(
      user,
      (newValue, oldValue) => {
        changeCount.value++
        console.log('User object changed:', newValue)
        // Save to API or localStorage
      },
      { deep: true }
    )

    // Watch specific nested property
    watch(
      () => user.value.address.city,
      (newCity, oldCity) => {
        console.log(`City changed from ${oldCity} to ${newCity}`)
      }
    )

    return { user, changeCount }
  }
}
</script>

The watch function with { deep: true } monitors all nested properties recursively. Any change at any nesting level triggers the watcher. This is useful for forms, complex state objects, or configuration objects. For better performance, watch specific nested properties using a getter function when you only need to track certain fields. Deep watchers have a performance cost with very large objects, so use them judiciously.

Best Practice Note

This is the same deep watching pattern we use in CoreUI Vue components for complex form validation. For very large objects, consider watching specific paths instead of the entire object. Use immediate: true option to run the watcher on component mount. For tracking which specific property changed, you may need to implement custom deep comparison logic.


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

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
How to Add a Tab in HTML
How to Add a Tab in HTML

How to return multiple values from a JavaScript function
How to return multiple values from a JavaScript function

How to fix “SyntaxError: Cannot use import statement outside a module”?
How to fix “SyntaxError: Cannot use import statement outside a module”?

How to compare dates with JavaScript
How to compare dates with JavaScript

Answers by CoreUI Core Team