refresh & refreshNuxtData

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.

4 min read Level 2/5 #nuxt#fetching#refresh
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
  }
}
Watching Reactive Sources →