Vue 3.5 Reactivity Overhaul: How the New Reactivity Transform Works
Vue 3.5 introduces a powerful update to its reactivity system: Reactivity Transform.
This feature simplifies how we declare and use reactive state, helping us write cleaner and more intuitive logic.
In this post, we’ll break down how it works, walk through examples, and offer some opinions on when you should use it.
What is Reactivity Transform?
Reactivity Transform is a compiler-based syntax sugar that allows you to write reactivity-aware code without manually
wrapping variables using ref() or accessing them via .value.
Before:
import { ref } from 'vue';
const count = ref(0);
console.log(count.value);
After (with Reactivity Transform):
let count = $ref(0); console.log(count);
The compiler auto-generates the reactive wrappers and unwraps them behind the scenes.
Enabling Reactivity Transform
To use this feature, make sure you’re on Vue 3.5+ and that reactivityTransform is enabled in your build tooling.
- With Vite: enabled by default in
vite-plugin-vue - With Vue Loader: use the
reactivityTransform: trueoption
Basic Example: Counter Component
Here’s a simplified counter using Reactivity Transform:
<script setup>
let count = $ref(0);
function increment() {
count++;
}
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
This is much cleaner than using ref and .value everywhere. The compiler rewrites it to work as expected.
Working with Reactive Objects
Vue 3.5 also introduces $reactive() to replace reactive() with automatic unwrapping of inner refs.
<script setup>
let user = $reactive({
name: 'Alice',
age: 30,
});
function birthday() {
user.age++;
}
</script>
<template>
<p>{{ user.name }} is {{ user.age }} years old.</p>
<button @click="birthday">Happy Birthday!</button>
</template>
No need to worry about user.age.value—it just works.
Mixing with Traditional Refs
You can still use ref() and reactive() in the same file. Just don’t mix access patterns:
<script setup>
import { ref } from 'vue';
let count = $ref(0);
let traditional = ref('hello');
console.log(count); // fine
console.log(traditional); // still need traditional.value
</script>
Developer Opinion
The new reactivity transform is excellent for reducing boilerplate in small components or prototypes.
It’s also great for teams just starting with Vue 3, as it feels more intuitive. That said:
- It hides some complexity that can be important to understand when debugging.
- It introduces magic via compiler transforms, which may not be desirable in all teams or projects.
- It’s not currently supported in all tooling (e.g., Nuxt has partial support as of now).
💡 Best practice: Use it where it makes your code cleaner, but don’t abandon understanding the underlying reactivity model.
Should You Use Reactivity Transform?
| Use It If… | Avoid It If… |
|---|---|
| You want simpler, cleaner component logic | You need complete transparency and debuggability |
| Your team is new to Vue | You have complex reactivity patterns |
You’re working in SFCs with <script setup> | You rely on advanced typing or TS inference |
More Resources
- Vue Official Guide: Reactivity Transform
- Vue RFC: Reactivity Transform
- Understanding Vue Reactivity Fundamentals
- Vue Mastery on 3.5 Features
With Vue 3.5, the reactivity experience gets a big upgrade. Whether you’re writing new components or refactoring old ones, this feature can reduce friction and improve readability—just use it wisely.

