Reactive vs. Ref in Vue 3: What’s the difference?
Jakub Andrzejewski

Jakub Andrzejewski @jacobandrewsky

About: • Senior Developer • @GoogleDevExpert in Web Performance • @nuxt_js Team • Ambassador @Storyblok, @algolia, @cloudinary, @supabase • Teaching Vue | Nuxt | Perf

Location:
Wrocław, Poland
Joined:
Jun 20, 2021

Reactive vs. Ref in Vue 3: What’s the difference?

Publish Date: Dec 16 '24
43 11

Vue 3 introduced the Composition API, offering developers more flexible and powerful tools for managing reactivity in their applications.

Among these tools, reactive and ref are two key methods for creating reactive state. While they may appear similar at first glance, understanding their differences is essential for writing clean and efficient Vue code.

In this article, I would like to list differences between reactive and ref and provides practical examples to help you decide when to use each :)

Enjoy!

🤔 What is ref and reactive?

In order to be able to compare these two Vue 3 utilities, we would need to understand better what they are and how they work.

What is reactive?

reactive is a method provided by Vue 3 that creates a deeply reactive object. It converts an object’s properties into reactive data, meaning any changes to those properties will trigger updates in the UI. The syntax of reactive looks like following:

import { reactive } from 'vue';

const state = reactive({
  count: 0,
  user: {
    name: 'John Doe',
    age: 30
  }
});

state.count++; // Updates the UI
state.user.name = 'Jane Doe'; // Updates the UI
Enter fullscreen mode Exit fullscreen mode

reactive works best with objects including arrays and comes with deep reactivity which means that all nested properties of the object become reactive.

Use reactive when managing complex state that involves objects or arrays. It’s ideal for scenarios where you need to track multiple properties as part of a single state.

What is ref?

ref is another method provided by Vue 3, but it creates a reactive reference to a single value. Unlike reactive, ref is designed to handle primitive data types such as strings, numbers, and booleans, as well as individual objects. The syntax of ref looks like following:

import { ref } from 'vue';

const count = ref(0);
const userName = ref('John Doe');

count.value++; // Updates the UI
userName.value = 'Jane Doe'; // Updates the UI
Enter fullscreen mode Exit fullscreen mode

ref works for primitive values and single objects and comes with a reactive wrapper .value property that provides access to the actual value.

Use ref when managing a single reactive value or when you need reactivity for a non-object type, like a number or string.

🟢 Reactive vs. Ref

Now, that we know what are reactive and ref let's compare them to see what are the differences and use cases:

reactive ref
Purpose Reactive state for objects and arrays Reactive state for single values or objects
API Works directly with the object Requires .value to access or update values
Reactivity Depth Deep reactivity Deep reactivity
Simplicity Best for managing structured state Best for simple, isolated values

To better understand the differences, let's take a look at the following examples.

Example 1: Reactive Object vs. Ref for Primitive Values

import { reactive, ref } from 'vue';

const reactiveState = reactive({ count: 0 });
const refCount = ref(0);

// Incrementing values
reactiveState.count++; // Directly updates the object property
refCount.value++; // Updates the .value property
Enter fullscreen mode Exit fullscreen mode

Example 2: Reactive Array vs. Ref Array

const reactiveArray = reactive([1, 2, 3]);
const refArray = ref([1, 2, 3]);

reactiveArray.push(4); // Reactivity works on array mutations
refArray.value.push(4); // Need .value for array operations
Enter fullscreen mode Exit fullscreen mode

Example 3: Using Reactive for Nested State

const reactiveUser = reactive({
  profile: {
    name: 'Alice',
    age: 25
  }
});

const refUser = ref({
  profile: {
    name: 'Alice',
    age: 25
  }
});

reactiveUser.profile.age = 26; // Automatically reactive at all levels
refUser.value.profile.age = 26; // Requires .value
Enter fullscreen mode Exit fullscreen mode

Mixing reactive and ref

In real-world applications, you’ll often use reactive and ref together. For example, you might use reactive for managing a complex object and ref for a single state value.

const state = reactive({
  items: [],
  loading: ref(false)
});

state.loading.value = true;
state.items.push({ id: 1, name: 'Item 1' });
state.loading.value = false;
Enter fullscreen mode Exit fullscreen mode

This feature could probably be delivered by only one Vue 3 utility but creators of this amazing frameworks thought about that already and decided to split it to give us more flexibility :)

📖 Learn more

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:

Vue School Link

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉

✅ Summary

Both reactive and ref are powerful tools for managing reactivity in Vue 3, but they serve different purposes. Use reactive for structured, complex state and ref for isolated or primitive values. By understanding their differences, you can choose the right tool for the right job, leading to cleaner and more maintainable code.

Experiment with both in your projects to find the balance that works best for your development style.

Take care and see you next time!

And happy coding as always 🖥️

Comments 11 total

  • Alois Sečkár
    Alois SečkárDec 16, 2024

    From Vue docs:
    we recommend using ref() as the primary API for declaring reactive state

    There is literally no reason to ever use reactive anywhere. All my apps work fine with just refs. The only benefit I can see is you dont have to write .value in script sections. But on the other hand it has a number of confusing pitfalls.

    But that may be a matter of personal preference. But one more important remark - the ref() is also deeply reactive by default - check HERE. Your comparsion table is wrong. If you want shallow reactivity, you have shallowRef and shallowReactive

    • Jakub Andrzejewski
      Jakub AndrzejewskiDec 17, 2024

      Hey there,

      I don't use reactive that often too. For all my use cases, ref was definitely enough.

      REgarding the table, yes you are correct. I have fixed it in my example but forgot to fix in the table. Thanks for noticing that!

      • Alois Sečkár
        Alois SečkárDec 17, 2024

        For me, this is the most confusing thing about Vue for newcommers - Why would you have two nearly same things (from the user's perspective) for one purpose? How to choose the "right" one for my use case? So many questions...

        I believe the best we can do is to let reactive slowly die out.

        • Alexander Opalic
          Alexander OpalicDec 17, 2024

          You need to look into the source code to understand it truly.

          ref is using reactive behind the hood for all values that are not primitive (shallow).

          you could argue why reactive is public but behind the hood vue needs it

          see

          github.com/vuejs/core/blob/main/pa...

  • Greg, The JavaScript Whisperer
    Greg, The JavaScript WhispererFeb 16, 2025

    Are refs WeakMaps? Do you need to cleanup listeners in something like unMount or vue3 does this for you?

    • Jakub Andrzejewski
      Jakub AndrzejewskiFeb 17, 2025

      AFAIK, you don't need to clean up anything. Vue does many things automagically for us :)

  • Nevo David
    Nevo DavidApr 13, 2025

    Amazing article with helpful insights on Vue 3 reactivity tools! Which aspects of these tools do you find most impactful for simplifying code?

  • Soufiane Yousfi Mghari
    Soufiane Yousfi MghariApr 23, 2025

    Just a quick note about the last example—I think there's a small mistake. You don't need to use .value with state.loading, since reactive automatically unwraps ref properties. That means you can access and modify the ref directly without appending .value.

    Vue.js Doc: Additional Ref Unwrapping Details

    state.loading = true;

  • daniele
    danieleMay 9, 2025

    reactive({
    items: [],
    loading: ref(false)
    });

    Why using a ref inside a reactive obj (since there is already deep reactivity)?
    Is'n state.loading = true enough ?

  • vanderw
    vanderwMay 22, 2025

    Like in your code line "state.count++; // Updates the UI"

    My question is: Where is the "UI"?

Add comment