# Vue Methods vs Computed Properties: Core Differences and When to Use Each

> Understand the core differences between Vue methods and computed properties. Learn when to use each for efficient state derivation and imperative actions in VueJS development.

- Repository: [Vue/core](https://github.com/vuejs/core)
- Tags: deep-dive
- Published: 2026-02-16

---

**TLDR:** In Vue.js, **methods** are imperative functions that run on every invocation without caching, while **computed properties** are reactive, memoized getters that only re-evaluate when dependencies change. Use methods for actions and side effects; use computed properties for deriving state from reactive data efficiently.

Understanding when to use methods and computed properties in Vue is critical for application performance and architecture. In the `vuejs/core` repository, these features are implemented through distinct mechanisms in the reactivity and runtime-core packages. While both are declared in the component options object, they serve fundamentally different purposes in the component's reactivity system.

## How Vue Methods Work

Methods in Vue are simple functions registered under the `methods` option in `ComponentOptionsBase`. During component initialization, the runtime iterates over `options.methods` and binds each function to the component instance.

In [`packages/runtime-core/src/componentOptions.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/componentOptions.ts) (lines 91–118), the `applyOptions` function registers methods by binding them to the public instance proxy:

```typescript
ctx[key] = methodHandler.bind(publicThis)

```

This binding ensures that `this` inside any method refers to the component's public proxy, giving access to data, props, and other options. Methods are **not reactive**—they execute immediately when called and do not track dependencies or cache results.

### Characteristics of Methods

- **Imperative execution**: Run only when explicitly invoked (e.g., `@click="handleClick"`)
- **No caching**: Return values are calculated fresh on every call
- **Side-effect friendly**: Designed for mutating state, API calls, and event handling
- **Function syntax**: Must be called with parentheses in templates

## How Computed Properties Work

Computed properties are reactive getters defined under the `computed` option. Unlike methods, they leverage Vue's reactivity system through `ComputedRefImpl` in [`packages/reactivity/src/computed.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/computed.ts).

When a component initializes computed properties, `applyOptions` in [`packages/runtime-core/src/componentOptions.ts`](https://github.com/vuejs/core/blob/main/packages/runtime-core/src/componentOptions.ts) (lines 59–94) creates a `ComputedRefImpl` instance and defines it on the component proxy:

```typescript
Object.defineProperty(ctx, key, {
  get: () => c.value,
  set: v => (c.value = v)
})

```

The `ComputedRefImpl` class tracks reactive dependencies accessed during the getter execution. As implemented in [`packages/reactivity/src/computed.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/computed.ts) (lines 31–40), the computed value only recalculates when dependencies change via the `refreshComputed` mechanism; otherwise, it returns the cached result.

### Characteristics of Computed Properties

- **Reactive caching**: Results are memoized until dependencies mutate
- **Property syntax**: Accessed as values (`{{ total }}`) without parentheses
- **Pure derivations**: Intended for transforming reactive data without side effects
- **Automatic updates**: UI re-renders automatically when cached value becomes dirty

## Key Differences

| Feature | Methods | Computed Properties |
|---------|---------|---------------------|
| **Reactivity** | Non-reactive; no dependency tracking | Reactive; tracks all dependencies in getter |
| **Caching** | No caching; executes on every call | Memoized; only re-evaluates when deps change |
| **Template Usage** | Called as functions (`@click="submit()"`) | Accessed as properties (`{{ fullName }}`) |
| **Side Effects** | Appropriate for mutations and I/O | Discouraged; should be pure functions |
| **Binding** | Bound via `methodHandler.bind(publicThis)` | Getter/setter bound via `getter.bind(publicThis)` |

## When to Use Each Approach

### Use Methods For:

- **Event handling**: Responding to user interactions like clicks, submits, or input events
- **Mutations**: Changing component state or calling APIs when explicit action occurs
- **Parameterization**: Logic that requires arguments passed at call time
- **Imperative operations**: Tasks that should run on-demand rather than automatically

### Use Computed Properties For:

- **Derived state**: Calculating values based on existing reactive data (e.g., filtering lists, formatting dates)
- **Expensive calculations**: Operations that should avoid redundant execution through caching
- **Read-only or writable derived data**: Two-way computed properties that sync with source data
- **Template optimization**: Reducing render overhead by caching complex transformations

## Practical Implementation Example

The following example demonstrates both patterns in a `<script setup>` component:

```typescript
<script setup lang="ts">
import { ref, computed } from 'vue'

const count = ref(1)

// Computed property: cached, reactive derivation
const double = computed(() => count.value * 2)

// Writable computed: two-way data flow
const half = computed({
  get: () => count.value / 2,
  set: (val) => (count.value = val * 2)
})

// Method: imperative action, no caching
function increment() {
  count.value++
}
</script>

<template>
  <p>Count: {{ count }}</p>
  <p>Double (computed): {{ double }}</p>
  <input v-model.number="half" type="number" placeholder="Half value" />
  <button @click="increment">Increment via method</button>
</template>

```

In this implementation, `double` creates a `ComputedRefImpl` instance that tracks `count` as a dependency, while `increment` is bound to the instance context and executes only when the button triggers it.

## Summary

- **Methods** are bound functions stored in the component context (`ctx`) via `methodHandler.bind(publicThis)`, executing on every call without caching or dependency tracking.
- **Computed properties** are `ComputedRefImpl` instances created by the `computed` API, offering reactive caching through dependency tracking and `refreshComputed` logic.
- Use **methods** for actions, event handlers, and side effects that must run on demand.
- Use **computed properties** for deriving reactive state, optimizing expensive calculations, and ensuring efficient template updates.

## Frequently Asked Questions

### Are computed properties cached in Vue?

Yes. According to the source code in [`packages/reactivity/src/computed.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/computed.ts), computed properties use `ComputedRefImpl` to cache results. The getter only re-executes when tracked dependencies change; otherwise, it returns the cached value immediately.

### Can I pass arguments to computed properties?

No. Computed properties are accessed as values, not functions, so they cannot accept runtime arguments. If you need parameterized logic, use a **method** instead, or create a computed property that returns a function (though this loses caching benefits for the inner function).

### When should I use a method instead of a computed property?

Use a **method** when performing actions that change state, handling events, or executing logic that requires arguments. Methods run on every invocation and are ideal for side effects. Use a **computed property** only when deriving a value from existing reactive data without side effects.

### Do methods and computed properties both have access to `this`?

Yes. Both are bound to the component instance during initialization. Methods are bound via `methodHandler.bind(publicThis)` in [`componentOptions.ts`](https://github.com/vuejs/core/blob/main/componentOptions.ts), while computed getters are bound via `getter.bind(publicThis, publicThis)`. However, in Composition API with `<script setup>`, you typically access reactive refs directly rather than through `this`.