The Right Way to Fetch Parallel Requests in Nuxt
When building a Nuxt application, you'll often need to fetch data from multiple APIs at the same time. A common approach is to use Promise.all()
to run these requests in parallel, aiming for better performance.
However, doing it the wrong way will lead to some issues. Let's dive into the examples below to see what issues it might cause.
🚫 The Wrong Way: Raw Promise.all
const [latestAlbums, featuredAlbums, featuredArtists] = await Promise.all([
$fetch("/api/albums/latest"),
$fetch("/api/albums/featured"),
$fetch("/api/artists/featured"),
]);
While this seems simple and efficient, it has a major issue in server-side rendering (SSR). Nuxt will first fetch the data on the server, and then again on the client after hydration—leading to unnecessary duplicate requests.
Using useFetch
inside the Promise.all
You might want to say "We can just use useFetch
then", but it's not a good solution either.
const [latestAlbums, featuredAlbums, featuredArtists] = await Promise.all([
useFetch("/api/albums/latest"),
useFetch("/api/albums/featured"),
useFetch("/api/artists/featured"),
]);
At first glance, this looks better because useFetch
should be only called on the server. However, if you try to do this, it will still result in duplicate requests in SSR.
✅ The Correct Way: useAsyncData
with Promise.all
The solution is to wrap Promise.all
inside useAsyncData
and then create computed properties for each data we want to use.
const { data } = await useAsyncData(() =>
Promise.all([
$fetch("/api/albums/latest"),
$fetch("/api/albums/featured"),
$fetch("/api/artists/featured"),
]),
);
const latestAlbums = computed(() => data.value[0] ?? []);
const featuredAlbums = computed(() => data.value[1] ?? []);
const featuredArtists = computed(() => data.value[2] ?? []);
This is the best approach because we are using useAsyncData
to fetch the data once on the server and then it will be present on the client side without any additional client-side requests.
🚀 Conclusion
If you're using Nuxt and need to fetch multiple APIs in parallel, avoid using raw Promise.all
or useFetch
directly. Instead, wrap Promise.all
inside useAsyncData
to get optimized, SSR-friendly, and efficient data fetching. This approach ensures your app runs smoothly while avoiding unnecessary network requests.