Chapter 59: Vue $data Object
The $data object
This is not something you use often in modern Vue 3 code, but it still exists, and understanding it properly will save you from a lot of confusion when you read legacy code, debug old projects, or see certain warnings/errors.
Let me explain it like Iām sitting next to you, showing you both the old world and the new world side by side.
1. What is $data? (The Honest 2026 Explanation)
$data is the internal object that Vue uses to store all the reactive data defined in the Options API data() function.
In Vue 2 and early Vue 3 (Options API style), when you wrote:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
export default { data() { return { count: 0, name: 'Rahul', isLoading: false, user: { age: 28, city: 'Hyderabad' } } } } |
Vue internally did something like this:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
this.$data = { count: 0, name: 'Rahul', isLoading: false, user: { age: 28, city: 'Hyderabad' } } |
And then made $data reactive ā so any change to this.count actually changed this.$data.count.
2. Where do you see $data in real life?
You almost never write $data yourself in modern code ā but you see it in these situations:
- Vue Devtools ā it shows the componentās $data section
- Console logging this in Options API
- Error messages / warnings
- Old tutorials / legacy code
- Accessing data in certain lifecycle hooks or plugins
- Debugging when something is unexpectedly undefined
3. Modern Vue 3 (<script setup>) ā You Almost Never See $data
In <script setup> (the 2026 standard), there is no $data object exposed to you.
|
0 1 2 3 4 5 6 7 8 9 10 11 |
<script setup> import { ref, reactive } from 'vue' const count = ref(0) const user = reactive({ name: 'Rahul', city: 'Hyderabad' }) </script> |
Vue still creates an internal data structure behind the scenes ā but you never touch $data. Everything is just normal JavaScript variables at the top level.
4. Real Side-by-Side Comparison (Options API vs Composition API)
Options API (old style ā you will still see this in many projects)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<template> <div> <p>Count: {{ count }}</p> <button @click="count++">+1</button> <p>Name: {{ user.name }}</p> </div> </template> <script> export default { data() { return { count: 0, user: { name: 'Rahul', city: 'Hyderabad' } } }, mounted() { console.log(this.$data) // ā { count: 0, user: {ā¦} } console.log(this.$data.count) // 0 console.log(this.count) // same as this.$data.count } } </script> |
Composition API / <script setup> (modern style ā 2026 default)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<template> <div> <p>Count: {{ count }}</p> <button @click="count++">+1</button> <p>Name: {{ user.name }}</p> </div> </template> <script setup> import { ref, reactive } from 'vue' const count = ref(0) const user = reactive({ name: 'Rahul', city: 'Hyderabad' }) console.log(count) // RefImpl object console.log(count.value) // 0 console.log(user) // Proxy { name: 'Rahul', city: 'Hyderabad' } console.log(user.name) // 'Rahul' // No $data here ā you never see or use it </script> |
5. When You Actually Might Touch $data (Rare in 2026)
You will see $data in these situations:
-
Vue Devtools
- Open Devtools ā select a component ā āDataā tab ā shows $data
-
Legacy Options API code
JavaScript0123456789mounted() {console.log(this.$data.user.name) // old style// same as this.user.name} -
Some plugin / mixin code
JavaScript012345678910111213// old mixinexport default {created() {if (this.$data.isLoading === undefined) {this.$data.isLoading = false}}} -
Debugging weird reactivity bugs
JavaScript0123456console.log(this.$data === this) // false ā but $data contains all your data properties
6. Quick Summary Table ā $data in 2026
| Question | Options API (old) | Composition API (<script setup>) | What you should do |
|---|---|---|---|
| Do I write $data? | Rarely ā this.$data.count | Never | Use count.value |
| Is it exposed in template? | Yes ā {{ $data.count }} works (ugly) | No ā use {{ count }} | Never use $data in template |
| Where do you see it most? | Vue Devtools, legacy code, old tutorials | Vue Devtools (internal view) | Ignore it mostly |
| Can I mutate it directly? | Yes (but donāt ā use this.count) | Not exposed ā use normal variables | Donāt touch it |
| Still exists in Vue 3? | Yes (for Options API) | Internal only ā not exposed to you | ā |
Final 2026 Advice (from real projects)
- In new code ā you will never write $data ā just use ref, reactive, computed, etc.
- When you see $data in code ā it means someone is using Options API (legacy style)
- When debugging ā look at Vue Devtools ā Data tab ā it shows the equivalent of $data even in Composition API
- Never teach beginners $data as something they should use ā it confuses them
- If you see this.$data in modern code ā itās usually a red flag (someone mixing old & new styles)
Your mini homework:
- Create a simple component in Options API ā log this.$data in mounted
- Convert it to <script setup> ā see that $data is no longer accessible (and you donāt need it)
- Open Vue Devtools on both ā compare how data looks
Any part still confusing? Want to see:
- Full Options API vs Composition API side-by-side project?
- How $data looks in Vue Devtools?
- Common bugs when people misuse this.$data in legacy code?
- Why Pinia / composables replaced most uses of shared $data?
Just tell me ā we’ll debug and compare together step by step š
