
Vue 3 Reactivity: Proxies vs. Vue 2 Reactivity

One of the biggest improvements in Vue 3 is its completely redesigned reactivity system. While effective, Vue 2's reactivity system had some notable limitations, especially when working with arrays or dynamically adding properties. Vue 3 leverages JavaScript's built‑in Proxy feature to solve many of these issues.
In this article, I intend to explore the differences between Vue 2's reactivity approach and Vue 3's use of Proxies and explain how each system works and why Vue made the switch.
How Reactivity Worked in Vue 2
Before looking at Vue 3's improvements, it makes sense for us to briefly revisit how Vue 2's reactivity works.
Vue 2: Object.defineProperty()
In Vue 2, the reactivity system relied heavily on JavaScript's Object.defineProperty() method (which I've written about in the past here). This method defines getters and setters on object properties, allowing Vue to detect and respond to changes, like this:
const data = {};Object.defineProperty(data, 'message', { get() { console.log('Accessing message'); return 'Hello'; }, set(newValue) { console.log('Updating message to:', newValue); },});Whenever the message property is changed or accessed, Vue's reactive system notices and updates the DOM accordingly.
Limitations of Vue 2 Reactivity
This approach has a few limitations:
- New properties added after initialisation are not reactive.
- Array modifications require special methods (
push,splice, etc.) to trigger updates. - It cannot detect changes to properties that weren't initially defined.
These limitations would often lead to developers using hacks and workarounds, which in turn makes those applications harder to maintain and less intuitive.
How Vue 3 Uses Proxies for Reactivity
Vue 3 addresses these shortcomings by using JavaScript Proxies, which are much more powerful, flexible, and better‑suited than getters and setters.
What are JavaScript Proxies?
A Proxy is an object which wraps another object (the 'target') and then intercepts operations such as reading, writing, or deleting properties. It can then handle these operations or pass them through to the underlying object.
Here's a quick example:
const target = { message: 'Hello' };const proxy = new Proxy(target, { get(target, prop) { console.log(`Property "${String(prop)}" read.`); return target[prop]; }, set(target, prop, value) { console.log(`Property "${String(prop)}" updated to "${value}"`); target[prop] = value; return true; },});console.log(proxy.message); // logs "Hello"proxy.message = 'Hi!'; // triggers setterIn Vue 3, this means that the underlying framework can track changes and modifications far more efficiently than before.
How Vue 3 Uses Proxies for Enhanced Reactivity
By adopting Proxies, Vue 3's reactivity system provides several advantages:
Dynamic Property Reactivity
Properties added after initialisation become reactive automatically, for example:
const state = Vue.reactive({});// Adding a new reactive property dynamicallystate.newMessage = 'Hello Vue!';This means that Vue 3 immediately tracks and responds to a new property, something that Vue 2 could not easily do.
Better Array Reactivity
Arrays in Vue 3 become fully reactive by default. All standard array operations are tracked automatically without needing those hacky special methods:
const state = reactive({ items: ['a', 'b', 'c'] });state.items.push('d'); // Vue 3 detects this automaticallyAs you can probably see, this is a far simpler and cleaner approach compared to Vue 2's use of special array methods like Vue.set() or array mutation.
Comparing Vue 2 and Vue 3 Reactivity
To summarise, here's a brief overview of the main differences between the two approaches:
| Feature | Vue 2 Reactivity | Vue 3 Reactivity |
|---|---|---|
| Implementation | Getters/Setters | JavaScript Proxies |
| New Properties | Require manual initialisation | Automatically reactive |
| Array Reactivity | Limited, special methods needed | Fully reactive without workarounds |
| Performance | Moderate performance overhead | Better performance due to native Proxy |
| Browser Support | Wider browser compatibility | Requires modern browsers |
Browser Support and Polyfills
You will probably have spotted in that table above, the potential pitfall with this approach is browser support. Because Vue 3's reactivity system relies on JavaScript proxies, it limits browser support to more modern browsers only. These are:
- Chrome 49+
- Firefox 18+
- Edge 12+
- Safari 10+
Realistically, these are browsers that are already at least ten years old, but if your application does still need to support older browsers, then you'll need to include polyfills or otherwise consider sticking with Vue 2's reactivity for maximum compatibility.
Wrapping up
Vue 3's shift to JavaScript proxies represents a major improvement in how reactive data is managed. Proxies have removed many of the limitations faced by Vue 2's getter‑and‑setter approach, which has simplified the creation of reactive applications. This change not only improves our experience with the framework as developers but also enhances performance and flexibility when building dynamic, interactive UIs.
Key Takeaways
- Vue 2 used getters and setters (
Object.defineProperty) to track changes, leading to certain limitations. - Vue 3 uses JavaScript proxies, offering improved flexibility and automatic reactivity.
- Newly added properties and array operations become automatically reactive in Vue 3.
- Proxies simplify reactivity, improve performance, and make state management more intuitive.
- Browser support for proxies is strong, but older browsers require polyfills or fallbacks.
Understanding this shift to proxies gives us greater control and efficiency when building Vue applications, resulting in smoother development and more responsive interfaces.
Related Articles

Understanding the Difference Between <b> and <strong>. Understanding the Difference Between

Object Control in JavaScript: defineProperties(). Object Control in JavaScript:
defineProperties()
Harnessing JavaScript's defineProperty(). Harnessing JavaScript's
defineProperty()
Building a Custom Vue 3 Hook Using the Composition API. Building a Custom Vue 3 Hook Using the Composition API

Renaming and Destructuring Variables in ES6. Renaming and Destructuring Variables in ES6

Why I’m the Best Choice for Web Development Near You. Why I'm the Best Choice for Web Development Near You

Automatically Generate Text Sitemaps in Gatsby. Automatically Generate Text Sitemaps in Gatsby

Creating Custom Viewport Units Instead of Using vh and vw. Creating Custom Viewport Units Instead of Using
vhandvw
Manipulate Elements with CSS transform. Manipulate Elements with CSS
transform
Use Greater‑Than and Less‑Than Symbols in JSX. Use Greater‑Than and Less‑Than Symbols in JSX

Creating Custom Vue Directives for Enhanced Functionality. Creating Custom Vue Directives for Enhanced Functionality

Graph Traversal: Solving the 'Course Schedule' Problem. Graph Traversal: Solving the 'Course Schedule' Problem