# Is It Bad Practice to Use a Computed Property Inside Another Computed Property in Vue 3?

> Discover if nesting computed properties in Vue 3 is bad practice. Learn how to compose reactive state effectively and avoid common pitfalls with computed properties.

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

---

**No, nesting computed properties in Vue 3 is fully supported and considered idiomatic for composing reactive state, provided you avoid circular dependencies and keep getters pure.**

The vuejs/core repository implements computed properties as first-class reactive primitives designed explicitly for this pattern. When you access one computed property inside another, Vue 3's reactivity system automatically establishes a subscription link between them, enabling efficient, lazy-evaluated dependency chains.

## How Vue 3 Handles Nested Computed Properties

Vue 3 treats computed properties as special subscribers that track reactive dependencies through a sophisticated flag-based system. Understanding this mechanism confirms why nesting is architecturally sound.

### The ComputedRefImpl Architecture

When you call `computed()`, Vue creates a `ComputedRefImpl` instance defined in [`packages/reactivity/src/computed.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/computed.ts). This object stores the getter function, a `Dep` object for tracking subscribers, and internal flags (`DIRTY`, `TRACKING`, etc.) that manage caching state. The implementation ensures that computed properties behave both as reactive data sources (when read) and as reactive consumers (when executing their getters).

### Automatic Dependency Tracking

When an outer computed property's getter reads the `.value` of an inner computed, the system invokes `Dep.track()` from [`packages/reactivity/src/dep.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/dep.ts). This operation links the outer computed as a subscriber to the inner computed's `Dep` object. According to the vuejs/core source code, this creates a directed acyclic graph of reactive dependencies where changes propagate efficiently downstream.

### Lazy Re-evaluation via refreshComputed

The `refreshComputed()` function in [`packages/reactivity/src/effect.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/effect.ts) drives the recomputation logic. When you access a nested computed chain, Vue checks the `EffectFlags.DIRTY` flag. If any upstream dependency—including an inner computed property—has a newer version, the outer property re-evaluates. Because evaluation is lazy, the getter runs only when `.value` is accessed, preventing wasteful recalculations during intermediate state changes.

## When Nested Computed Properties Cause Problems

While the pattern is generally safe, three specific anti-patterns can introduce bugs or performance issues.

### Circular Dependencies

Circular references occur when computed property A depends on B, which depends on A. Vue detects this scenario using the `EffectFlags.RUNNING` flag during `refreshComputed`. When a computed attempts to re-evaluate while already running, the system returns early to prevent stack overflow, but the result will be stale. Development builds emit a warning when this happens.

```typescript
import { ref, computed } from 'vue'

const count = ref(1)

// BAD: Circular dependency
const c1 = computed(() => c2.value + 1)
const c2 = computed(() => c1.value + 1)

console.log(c1.value) // Undefined with dev warning

```

Break cycles by extracting shared logic into plain functions or non-computed refs.

### Side Effects in Getters

Computed getters must remain pure functions. Side effects (like API calls or mutations) break Vue's caching guarantees and may execute unpredictably during dependency tracking. The reactivity system assumes getters are deterministic, so side effects do not integrate with the `Dep` notification system.

### Deep Synchronous Chains

Nesting many computed layers with heavy synchronous work can cause cascade re-computations when deep dependencies change. While Vue's lazy evaluation minimizes overhead, accessing the outermost property still triggers evaluation of the entire chain. For expensive transformations across multiple layers, consider using `watch` or memoization utilities.

## Practical Examples

### Basic Nesting (Recommended)

This pattern demonstrates idiomatic composition where an outer computed automatically subscribes to an inner one.

```typescript
import { ref, computed } from 'vue'

const base = ref(2)

const double = computed(() => base.value * 2)
const triple = computed(() => double.value + base.value)

console.log(triple.value) // 6
base.value = 3
console.log(triple.value) // 9 (double recomputed, then triple)

```

The outer `triple` tracks `double`'s `Dep`. When `base` changes, `double` marks itself dirty; the next read of `triple.value` triggers fresh evaluation of both levels.

### Circular Dependency (Avoid)

```typescript
import { ref, computed } from 'vue'

const a = ref(1)

const c1 = computed(() => c2.value + 1) // depends on c2
const c2 = computed(() => c1.value + 1) // depends on c1

console.log(c1.value) // Dev warning: "Computed is already running"

```

Vue prevents infinite recursion but leaves the result undefined. Refactor to eliminate the cycle.

### Expensive Computations with Watch

For heavy logic, nested computed properties remain efficient but benefit from explicit observation.

```typescript
import { ref, computed, watch } from 'vue'

const numbers = ref([1, 2, 3, 4, 5])

const sumOfSquares = computed(() => {
  console.log('recomputing squares')
  return numbers.value.reduce((sum, n) => sum + n * n, 0)
})

const offsetSum = computed(() => sumOfSquares.value + 10)

watch(offsetSum, (newVal) => {
  console.log('Final result:', newVal)
})

numbers.value.push(6) // sumOfSquares recomputes only when offsetSum is accessed

```

Even with multiple layers, each level recomputes only when its direct dependencies change and the value is actually read.

## Summary

- **Nested computed properties are idiomatic** in Vue 3 and implemented intentionally in [`packages/reactivity/src/computed.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/computed.ts).
- **Dependency tracking is automatic** via `Dep.track()` in [`packages/reactivity/src/dep.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/dep.ts), creating efficient subscription links between computed layers.
- **Evaluation is lazy** through `refreshComputed()` in [`packages/reactivity/src/effect.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/effect.ts), ensuring getters run only when necessary.
- **Avoid circular dependencies** which trigger `EffectFlags.RUNNING` detection and produce stale results.
- **Keep getters pure** to maintain caching guarantees and predictable reactivity behavior.

## Frequently Asked Questions

### Can I use a computed property inside another computed property in Vue 3?

Yes, this is standard practice. Vue 3's reactivity system explicitly supports this pattern through the `ComputedRefImpl` class, which tracks dependencies via `Dep` objects. When an outer computed reads an inner computed's `.value`, it subscribes to changes automatically.

### Does nesting computed properties hurt performance?

No, nesting does not inherently hurt performance because Vue uses lazy evaluation. Computed properties only re-evaluate when accessed after their dependencies change. However, extremely deep chains with expensive synchronous operations can cause cascade delays; in such cases, consider using `watch` or extracting logic into methods.

### How does Vue 3 detect circular dependencies in computed properties?

Vue checks the `EffectFlags.RUNNING` flag during `refreshComputed()` in [`packages/reactivity/src/effect.ts`](https://github.com/vuejs/core/blob/main/packages/reactivity/src/effect.ts). If a computed property attempts to execute while already running, the system returns early to prevent infinite recursion. Development builds emit a warning when circular dependencies are detected.

### Should I use methods instead of nested computed properties?

No, use methods only when the result should not be cached or does not depend on reactive state. Computed properties are optimized for derived state that depends on other reactive values. Nesting them provides better performance through memoization and clearer semantic intent than equivalent method calls.