Optimizing calls to DatoCMS
Next.js 15 and Later
Starting with Next.js 15, fetch is no longer auto-cached. It is now an opt-in mechanism. Please see the Next 15 caching docs for details.
Next.js 14
Although the Next.js fetch API has (almost) the same interface as the regular fetch available on the browser, it is important to highlight some key differences, which might cause some surprise.
Next.js 14 automatically caches fetches
By default, Next.js automatically caches your fetches:
For
fetchcalls happening in Server Components, this means that the data will be fetched at build time, cached, and reused indefinitely on each request until your next deploy.For
fetchcalls happening in Client Components, the cache lasts the duration of a session (which could include multiple client-side re-renders) before a full page reload.
Caching requests is generally a good idea, as it minimizes the number of requests made to DatoCMS. However, if you want to always fetch the latest data, you can mark requests as dynamic and fetch data on each request without caching.
GraphQL calls need to be manually cached
The automatic caching only works for GET requests. Since GraphQL requests use a POST HTTP action, we need to manually handle CDA caching ourselves.
For this purpose, we can use a useful helper that React offers called cache, which memoizes the result of the passed function: Next.js: React Cache Function.
Our improved performRequest
Based on what we have just learned, we can refine our performRequest function, and make it more flexible and optimized:
import { executeQuery } from '@datocms/cda-client';import { cache } from 'react';
const dedupedPerformRequest = cache(async (serializedArgs) => { return executeQuery(...JSON.parse(serializedArgs));})
export function performRequest(query, options) { return dedupedPerformRequest(JSON.stringify([ query, { ...options, token: process.env.NEXT_DATOCMS_API_TOKEN, environment: process.env.NEXT_DATOCMS_ENVIRONMENT, }, ]);}This new version dedupes your GraphQL requests, supports all CDA header modes, and lets you control if — and for how long — you want to cache the result of the query with the revalidate option:
// cache the query result indefinitely (until next deploy)await performRequest(query);
// cache the query result for a maximum of 60 secondsawait performRequest(query, requestInitOptions: { next: { revalidate: 60 } });