When using the app router in Next.js v13+, AJAX requests made with fetch
are automatically cached. However, if you're fetching data from a database (such as with Prisma, or other databases), automatic deduplication does not occur. To deduplicate database calls, you can follow these steps:
- Extract the function responsible for making database calls into a separate function, and;
- Wrap this function with
React.cache()
(available in React v18+).
For instance, suppose you're making the same database call twice to retrieve blog post data for both, generateMetadata()
and the Next.js page, as shown below:
// page.js
import { fetchPostById } from '@/service/posts.service';
export async function generateMetadata() {
const post = await fetchPostById(1);
return {
title: post.title,
// ...
}
}
export default async function BlogPostPage() {
const post = await fetchPostById(1);
return (
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>
)
}
To ensure only one request is made to the database everytime you open this page (with subsequent calls using the cached version), you can use React.cache()
as follows:
// page.js
import { cache } from 'react';
import { fetchPostById } from '@/service/posts.service';
// 1: extract the function with database calls into a separate function
// 2: wrap that function with `React.cache()`
const fetchPostByIdWrapper = cache(async (id) => fetchPostById(id));
export async function generateMetadata() {
const post = await fetchPostByIdWrapper(1);
return {
title: post.title,
// ...
}
}
export default async function BlogPostPage() {
const post = await fetchPostByIdWrapper(1);
return (
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>
)
}
When you wrap the function with React.cache()
, upon the initial database read operation, there will be a "cache miss", and the data will be fetched from the database. Subsequent requests for the same read operation, however, will result in a "cache hit", returning the cached data.
To verify if this works as intended, you can log all database operations and check your Next.js app's console output to determine if the specific query is being executed once or twice. For instance, when using Prisma, you can include the following option when instantiating the PrismaClient
to log all database operations:
const prisma = new PrismaClient({
log: ['query', 'info', 'warn', 'error'],
});
This will output all Prisma logs, allowing you to verify if the query of interest is being executed once or twice.
This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.