Re-Run Fetches After a Mutation
refresh & refreshNuxtData
After a write, call refresh from useFetch or refreshNuxtData by key to update cached data without a full navigation.
What you'll learn
- Destructure refresh from useFetch and call it after mutations
- Use refreshNuxtData with a key to invalidate any matching cache
- Combine refresh with optimistic UI patterns
After a POST/PUT/DELETE, you usually want to re-display the freshly mutated data. Nuxt offers two ways to invalidate cached results.
refresh from useFetch
Every useFetch returns a refresh function tied to that specific call:
<script setup lang="ts">
const { data: posts, refresh } = await useFetch('/api/posts')
const title = ref('')
async function addPost() {
await $fetch('/api/posts', { method: 'POST', body: { title: title.value } })
title.value = ''
await refresh()
}
</script>
<template>
<input v-model="title" />
<button @click="addPost">Add</button>
<ul><li v-for="p in posts" :key="p.id">{{ p.title }}</li></ul>
</template> refreshNuxtData by Key
When the mutation happens far away from the useFetch call site, target by key:
// Page A
const { data } = await useAsyncData('posts', () => $fetch('/api/posts'))
// Page B (or a global store)
await $fetch('/api/posts', { method: 'POST', body })
await refreshNuxtData('posts') // re-runs any useAsyncData with key 'posts' Call refreshNuxtData() with no args to refresh everything on the page.
Optimistic UI
Combine refresh with an immediate local update for a snappier feel:
async function addPost(title: string) {
// Optimistic insert
posts.value = [...posts.value, { id: Date.now(), title }]
try {
await $fetch('/api/posts', { method: 'POST', body: { title } })
} finally {
await refresh() // reconcile with server truth
}
}