javascript 31 lines · 6 steps

Deduping data fetches with React cache in Next.js

Wrapping loaders in React's cache() means each request fetches a project once, even when many components ask for it.

Explained by highlit
1import { cache } from 'react'
2import { notFound } from 'next/navigation'
3import { db } from '@/lib/db'
4 
5export const getProject = cache(async (slug) => {
6 const project = await db.project.findUnique({
7 where: { slug },
8 include: {
9 owner: { select: { id: true, name: true, avatarUrl: true } },
10 _count: { select: { tasks: true, members: true } },
11 },
12 })
13 
14 if (!project) notFound()
15 
16 return project
17})
18 
19export const getProjectMembers = cache(async (slug) => {
20 const project = await getProject(slug)
21 
22 return db.member.findMany({
23 where: { projectId: project.id },
24 orderBy: { joinedAt: 'asc' },
25 select: {
26 id: true,
27 role: true,
28 user: { select: { id: true, name: true, avatarUrl: true } },
29 },
30 })
31})
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Wrapping a server-side loader in cache() memoizes it per request so repeated calls hit the database only once.
  2. 2Cached loaders compose cleanly — one can call another and still reuse the first's memoized result.
  3. 3Calling notFound() inside a loader lets data access and 404 routing live in the same place.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Deduping data fetches with React cache in Next.js — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code