Why must data be a function in Vue components, and what breaks if it isn’t?

MediumIntermediateVue
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

In Vue, component data must be a function so each instance gets its own state object. If it were a shared object, multiple instances would mutate the same reference and leak state between components. This avoids shared state bugs and makes components safer to reuse and test.

Answer

Core idea

data() must be a function in reusable component definitions so Vue can create a new state object per component instance. If you use a plain object, every instance points to the same object reference (shared state).

data option

What Vue needs

What happens in practice

data() { return { ... } }

A factory that returns a new object per instance

Each component instance has isolated state

data: { ... }

A single object

All instances share the same state (cross-instance leaks)

Why Vue requires data() in components

What breaks if data is an object?

Nothing “crashes” immediately—Vue can still make it reactive—but your component stops being instance-safe. The bugs show up as state leaking between instances.

HTML
<!-- WRONG: shared state across instances -->
<script>
const Counter = {
  template: `
    <button @click="count++">Count: {{ count }}</button>
  `,
  data: { count: 0 } // ❌ shared reference
};

export default {
  components: { Counter }
};
</script>

<template>
  <Counter />
  <Counter />
</template>

<!-- Click one button -> both counters update because they share the same 'count'. -->
                  
HTML
<!-- CORRECT: per-instance state -->
<script>
const Counter = {
  template: `
    <button @click="count++">Count: {{ count }}</button>
  `,
  data() {
    return { count: 0 }; // ✅ new object per instance
  }
};

export default {
  components: { Counter }
};
</script>

<template>
  <Counter />
  <Counter />
</template>
                  

Scenario

Symptom

Why it happens

Rendering the same component multiple times

Changing state in one instance changes the others

All instances reference the same object

Lists (v-for) of stateful components

Items “share” state unexpectedly (especially with filtering/sorting)

Instances are supposed to be isolated; shared data violates that

SSR (Nuxt / server rendering)

Request-to-request state leakage between users

Server process reuses the same module/object across requests

Real-world breakages from shared component data

Rule of thumb

• If you want instance state (almost always): use data().
• If you want intentionally shared state: don’t “accidentally” share via data: {}—use a store (Pinia) or a clearly named shared module/composable.

Practical scenario
Rendering a list of card components, each needs isolated local state for toggles and counters.

Common pitfalls

      • Using a shared object for data and leaking state between instances.
      • Mutating data outside the component and causing side effects.
      • Assuming reactivity works the same for shared references.
Trade-off or test tip
Returning a function is slightly more boilerplate but safer. Test two instances to ensure state stays isolated.

Summary

Vue requires data() in component definitions because components are instantiated multiple times. A function returns a fresh object per instance. If data is a plain object, state becomes shared, causing cross-instance bugs and (in SSR) even cross-user data leaks.

Similar questions
Guides
15 / 34