According to the doc, useFetch.data should be a ref but it's a computed?
What I am missing?


10 Replies
Hi @Romain 'Maz' B.. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
Short answer: In Nuxt, the data returned by useFetch is a Vue ref. It may be implemented internally as a computed ref for features like shared/cached state and reactive invalidation, but its public type and usage are Ref (accessed with .value in script). The API docs specify data: Ref<DataT | undefined> as the return type, alongside error and status also being refs, while refresh/execute/clear are plain functions (useFetch – Return Values, useFetch – Type).
So, even if devtools show it as “computed,” you should treat it as a Ref in userland:
(Getting started: useFetch, API: useFetch, API: useFetch type)
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
<@601146927005827074> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
The fact is that I need to force the data to be a ref by re-assigning it like this to be fully reactive:
Is data a shallowRef @kapa.ai
Let me check the knowledge base for you again. One moment! :books:
----------------------
Yes. In Nuxt 4, data returned from useFetch/useAsyncData is a shallowRef by default. This means updates that replace the whole value trigger reactivity, but mutating nested properties does not. You can opt into deep reactivity per call with { deep: true } if needed.
Example:
(Shallow Data Reactivity in useAsyncData and useFetch, useFetch – Return Values)
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
<@601146927005827074> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Hmm, the deep option doesn't change anything @kapa.ai
Let me check the knowledge base for you again. One moment! :books:
----------------------
Two key points that can explain why setting deep: true “doesn’t change anything”:
- shallowRef vs deep: In Nuxt 4, data from useFetch/useAsyncData is shallow by default for performance. deep: true switches the ref itself to deep reactivity (so nested mutations can trigger updates), but this only affects how Vue tracks changes to data, not how data is shared/cached or when it refetches (Shallow Data Reactivity). If you’re mutating nested fields in place and still not seeing updates, ensure you actually passed deep: true to useFetch (or set it globally via experimental.defaults.useAsyncData.deep) and that you’re mutating the same data instance returned by useFetch (not a copy) (same source).
- Shared state and consistency: useFetch shares refs for the same key/URL+options across components. If any other call with the same key/URL used different deep/transform/pick/default/getCachedData options, Nuxt enforces option consistency and may warn, and behavior might not match your expectations. Ensure all calls with the same key/URL use consistent options or use a distinct key to isolate instances (Singleton Data Fetching Layer, Minimize payload size → Shared State and Option Consistency).
Quick checks:
- Use deep per call: const { data } = await useFetch('/api/posts', { deep: true }) (same “Shallow Data Reactivity” doc).
- If you need isolation, provide a unique key: useFetch('/api/posts', { key: 'posts-deep', deep: true }) to avoid shared shallow instances (Reactive Keys and Shared State).
- Don’t wrap the ref in ref again (ref(data)); use data directly and mutate nested properties only when deep: true. Otherwise, replace the whole value to trigger updates with shallow refs (e.g., data.value = { ...data.value, nested: { ... } }) (Shallow Data Reactivity).
If after setting deep: true it still behaves shallow, verify no other useFetch call with the same key/URL is providing conflicting options; if needed, give this call its own key to ensure the deep option applies to the instance you’re using (same sources above).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
<@601146927005827074> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Ok... The issue was not the useFetch deep true option but the nuxt-sanctum-auth module that I use in the project which override some of the native useFetch behavior including the deep true option...
btw,
posts here won't be reactive