Cache an API response in Nuxt

This feature was introduced in Nuxt 3.8
with the getCachedData
option.
What is this solving?
By default, when using useFetch or useAsyncData in Nuxt components, the data might be re-fetched every time you navigate back to a component (client-side navigation), even if the data hasn't changed or doesn't need refreshing immediately. This can lead to unnecessary API calls and potentially show different data, when the user might expect it to be consistent within their session.
What getCachedData Does
Introduced in Nuxt 3.8, getCachedData is an option you can pass to useFetch and useAsyncData. It's a function that allows you to define custom client-side caching logic. It essentially acts as a gatekeeper before the actual fetch handler (the API call or async function) is executed.
Example
Here's how I can fetch a user's preferences from the API and cache it using getCachedData, data is fetched on the first load and then cached in the client side.
<script setup lang="ts">
const nuxtApp = useNuxtApp();
await useFetch("/api/user-preferences", {
key: "user-preferences",
getCachedData(key) {
return nuxtApp.payload.data[key] || nuxtApp.static.data[key];
},
});
</script>
Taking it a step further - Adding a TTL to invalidate the cache
You can add a TTL (Time To Live) to the cache, so the data is refreshed after a certain period of time.
<script setup lang="ts">
const nuxtApp = useNuxtApp()
const { data } = await useFetch<UserPreferences>('/api/user-preferences', {
key: 'user-preferences',
transform(input) {
return {
...input,
fetchedAt: new Date()
}
},
getCachedData(key) {
const data = nuxtApp.payload.data[key] || nuxtApp.static.data[key]
// If data is not fetched yet
if (!data) {
// Fetch the first time
return
}
// Check if the data is older than 5 minutes
const expirationDate = new Date(data.fetchedAt)
expirationDate.setTime(expirationDate.getTime() + 5 * 60 * 1000) // 5 minutes TTL
const isExpired = expirationDate.getTime() < Date.now()
if(isExpired) {
// Refetch the data
return
}
return data
},
})
</script>
<template>
<div>
<h1>User Preferences</h1>
<div v-if="data">
<div>Theme: {{ data.theme }}</div>
<div>Language: {{ data.language }}</div>
<div>Notifications: {{ data.notifications ? 'Enabled' : 'Disabled' }}</div>
</div>
<NuxtLink to="/settings">Edit Preferences</NuxtLink>
</div>
</template>
useNuxtData
Once you have the data in the client side, you can use useNuxtData
to access it anywhere in your app.
const { data: userPreferences } = useNuxtData("user-preferences");
Neat right?
Video
FYI, this video by Alexander Lichter was super helpful to understand this feature better and I highly recommend you watch it.