Vue Computed Properties

Computed properties let you derive and cache reactive values from your component's data instead of recalculating them inside methods or templates.

What Problem Do Computed Properties Solve

Templates should stay declarative. Putting complex logic - filtering a list, formatting a date, combining several fields - directly inline makes templates hard to read and easy to duplicate. Computed properties move that logic into a single, named property that behaves just like a data property from the template's point of view.

Declaring a Computed Property

Computed properties are defined as functions on the computed option. Inside each function, this refers to the component instance, so you can read any data, prop, or other computed property. In the template, you access the result like a plain property, without parentheses.

A basic computed property

<div id="app">
  <p>Full name: {{ fullName }}</p>
  <input v-model="firstName" placeholder="First name" />
  <input v-model="lastName" placeholder="Last name" />
</div>

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
  const app = Vue.createApp({
    data() {
      return {
        firstName: 'Ada',
        lastName: 'Lovelace'
      }
    },
    computed: {
      fullName() {
        return this.firstName + ' ' + this.lastName
      }
    }
  })
  app.mount('#app')
</script>

Computed Properties vs Methods

Both computed properties and methods can return a derived value, but they behave differently. A computed property caches its result and only re-evaluates when one of the reactive values it reads actually changes. A method has no cache at all - it re-runs its entire body every single time it is called, even from the same render, even if nothing relevant changed.

Caching in action: computed vs method

<div id="app">
  <p>Filtered (computed): {{ expensiveList }}</p>
  <p>Filtered (method): {{ expensiveListMethod() }}</p>
  <button @click="clicks += 1">Re-render ({{ clicks }})</button>
</div>

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
  const app = Vue.createApp({
    data() {
      return {
        numbers: [3, 8, 12, 5, 20, 1],
        clicks: 0
      }
    },
    computed: {
      expensiveList() {
        console.log('computed: recalculating filtered list')
        return this.numbers.filter(n => n > 5)
      }
    },
    methods: {
      expensiveListMethod() {
        console.log('method: recalculating filtered list')
        return this.numbers.filter(n => n > 5)
      }
    }
  })
  app.mount('#app')
</script>
  • Computed properties are defined in the computed option and accessed like plain properties, without parentheses.
  • A computed property re-evaluates only when one of the reactive values read inside its getter changes.
  • A method runs its full body every single time it is called, even if nothing relevant to it has changed.
  • Computed properties should stay pure - given the same underlying data, they should always return the same result with no side effects.

Writable Computed Properties with get and set

A computed property can also be defined with the object form, providing both a get function and a set function. This is useful when a derived value needs to support two-way binding, such as v-model on a computed full name that writes back into separate first and last name fields.

A writable computed property

<div id="app">
  <p>Full name: {{ fullName }}</p>
  <input v-model="fullName" placeholder="Edit full name" />
  <p>First: {{ firstName }} | Last: {{ lastName }}</p>
</div>

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
  const app = Vue.createApp({
    data() {
      return {
        firstName: 'Grace',
        lastName: 'Hopper'
      }
    },
    computed: {
      fullName: {
        get() {
          return this.firstName + ' ' + this.lastName
        },
        set(newValue) {
          const parts = newValue.split(' ')
          this.firstName = parts[0] || ''
          this.lastName = parts[1] || ''
        }
      }
    }
  })
  app.mount('#app')
</script>
Note: Vue automatically tracks which reactive properties a computed getter reads during its first run, and only recalculates the value when one of those specific dependencies changes - you never have to declare a dependency list yourself.
AspectComputed PropertyMethod
CachingCached until a tracked dependency changesNever cached; runs on every call
Syntax in template{{ fullName }}{{ fullName() }}
Best forDerived values read many times per renderOne-off actions or values that must always recompute
Can have a setterYes, via the get/set object formNot applicable
Note: Avoid triggering side effects - API calls, timers, DOM mutations - inside a computed getter. Vue may call the getter multiple times or skip it entirely when cached, so side effects that must run in response to a change belong in a watcher instead.

Exercise: Vue Computed Properties

Why does Vue cache the result of a computed property?