Optimizing External API Calls in Next.js with ISR and graphql-request
Answered
Ojos Azules posted this in #help-forum
Ojos AzulesOP
I’m working on a Next.js application where I’m using Incremental Static Regeneration (ISR) to improve performance. However, I’m noticing a lot of external API hits, which is affecting the efficiency of my application. Here’s a breakdown of the current setup:
Header: Makes a global GraphQL call (external API).
Body: Makes a page-specific GraphQL call (external API).
Generate: Fetches metadata from an external API.
Footer: Makes another global GraphQL call (external API).
I’m using graphql-request for my GraphQL queries, so I can’t leverage Next.js’s built-in fetch caching. I’m looking for ways to use Next.js caching mechanisms to reduce the number of external API hits without switching to fetch.
Could you suggest strategies or best practices to cache these external API calls effectively while still using graphql-request? Any insights or examples would be greatly appreciated!
Header: Makes a global GraphQL call (external API).
Body: Makes a page-specific GraphQL call (external API).
Generate: Fetches metadata from an external API.
Footer: Makes another global GraphQL call (external API).
I’m using graphql-request for my GraphQL queries, so I can’t leverage Next.js’s built-in fetch caching. I’m looking for ways to use Next.js caching mechanisms to reduce the number of external API hits without switching to fetch.
Could you suggest strategies or best practices to cache these external API calls effectively while still using graphql-request? Any insights or examples would be greatly appreciated!
Answered by B33fb0n3
it looks like you are reusing your functions to get specific data, but nextjs does not dedupe the requests by default. You can wrap your unstable cache functions inside a
React.cache(() => { your code here })
to dedupe your requests. Btw, you might want to set your revalidate
to some value7 Replies
@Ojos Azules I’m working on a Next.js application where I’m using Incremental Static Regeneration (ISR) to improve performance. However, I’m noticing a lot of external API hits, which is affecting the efficiency of my application. Here’s a breakdown of the current setup:
Header: Makes a global GraphQL call (external API).
Body: Makes a page-specific GraphQL call (external API).
Generate: Fetches metadata from an external API.
Footer: Makes another global GraphQL call (external API).
I’m using graphql-request for my GraphQL queries, so I can’t leverage Next.js’s built-in fetch caching. I’m looking for ways to use Next.js caching mechanisms to reduce the number of external API hits without switching to fetch.
Could you suggest strategies or best practices to cache these external API calls effectively while still using graphql-request? Any insights or examples would be greatly appreciated!
for external APIs nextjs provides only one way to cache these: the
unstable_cache
. Yes, I know it's unstable, but it's waaaay more stable than the currently unstable 'use cache'
directive and it does the job pretty well. I personally never had issues with it and a lot of people from this server are using it, to cache external api calls (without fetch)Ojos AzulesOP
@B33fb0n3 Thanks for the reply. I did go to the documentation, and I think to use the
so i used
I'm using generateStaticParams as in the v15 app router, and
and on generate metadata as well with the same key in the cache
it shows cache has been updated too on Vercel dashboard
Image
but it always takes 3sec to navigate between page (ISR should be fast once cache)
and if I see a monitor of external api hit, it incerase like 5 number
use cache
option I have to turn on the experimental flag through the next config. so i used
unstable_cache
as well.I'm using generateStaticParams as in the v15 app router, and
const DynamicPage = async (props: { params: PagePropsTypes }) => {
const { slug } = await props.params
const cacheKey = `${slug ? slug.join('/') : 'home'}`
const pageUris =
(await sdk.GetPageUris()).pages?.nodes?.map((node) =>
normalizeUri(node!.uri!)
) ?? []
// disable cache for dev
const query = (await unstable_cache(
async () => await sdk.GetPage({ uri }),
[cacheKey],
{
tags: [cacheKey],
revalidate,
}
)()) as DeepRequired<GetPageQuery>
if (!query.page) return notFound()
and on generate metadata as well with the same key in the cache
export async function generateMetadata(props: { params: PagePropsTypes }) {
const { slug } = await props.params
const uri = slug ? `/${slug.join('/')}` : '/'
const cacheKey = `${slug ? slug.join('/') : 'home'}`
try {
// disable cache for dev
const query = (await unstable_cache(
async () => await sdk.GetPage({ uri }),
[cacheKey],
{
tags: [cacheKey],
revalidate,
}
)()) as DeepRequired<GetPageQuery>
it shows cache has been updated too on Vercel dashboard
Image
but it always takes 3sec to navigate between page (ISR should be fast once cache)
and if I see a monitor of external api hit, it incerase like 5 number
@Ojos Azules <@301376057326567425> Thanks for the reply. I did go to the documentation, and I think to use the `use cache` option I have to turn on the experimental flag through the next config.
so i used `unstable_cache ` as well.
I'm using generateStaticParams as in the v15 app router, and
const DynamicPage = async (props: { params: PagePropsTypes }) => {
const { slug } = await props.params
const cacheKey = `${slug ? slug.join('/') : 'home'}`
const pageUris =
(await sdk.GetPageUris()).pages?.nodes?.map((node) =>
normalizeUri(node!.uri!)
) ?? []
// disable cache for dev
const query = (await unstable_cache(
async () => await sdk.GetPage({ uri }),
[cacheKey],
{
tags: [cacheKey],
revalidate,
}
)()) as DeepRequired<GetPageQuery>
if (!query.page) return notFound()
and on generate metadata as well with the same key in the cache
export async function generateMetadata(props: { params: PagePropsTypes }) {
const { slug } = await props.params
const uri = slug ? `/${slug.join('/')}` : '/'
const cacheKey = `${slug ? slug.join('/') : 'home'}`
try {
// disable cache for dev
const query = (await unstable_cache(
async () => await sdk.GetPage({ uri }),
[cacheKey],
{
tags: [cacheKey],
revalidate,
}
)()) as DeepRequired<GetPageQuery>
it shows cache has been updated too on Vercel dashboard
Image
but it always takes 3sec to navigate between page (ISR should be fast once cache)
and if I see a monitor of external api hit, it incerase like 5 number
it looks like you are reusing your functions to get specific data, but nextjs does not dedupe the requests by default. You can wrap your unstable cache functions inside a
React.cache(() => { your code here })
to dedupe your requests. Btw, you might want to set your revalidate
to some valueAnswer
@Ojos Azules solved?
@B33fb0n3 <@634763003316928515> solved?
Ojos AzulesOP
yes, solved thank you, I didn't wrap with React.cache cause it was caching without, I think I miss cache for some endpoints, even on the above code. after this its been cache, I have revalidation of 10 minutes, i dont if it is too fast cause on extern api hit i see lots of number there .
@Ojos Azules yes, solved thank you, I didn't wrap with React.cache cause it was caching without, I think I miss cache for some endpoints, even on the above code. after this its been cache, I have revalidation of 10 minutes, i dont if it is too fast cause on extern api hit i see lots of number there .
yea, the most important thing is to dedupe the request (with React.cache) and using actual cache for the fetches
happy to help