Sequential data fetching
Sequential data fetching happens when one request depends on data from another. For example, when <Playlists> needs an artistID from getArtist() before it can fetch playlists. The page waits for the first request to complete before the second can start.
Sequential data fetching with Suspense
Example of sequential data fetching: await the first request (getArtist), pass its result to a Server Component wrapped in <Suspense>, and that component fetches the dependent data (getArtistPlaylists). The fallback is shown while the dependent component loads.
Parallel data fetching with Promise.all
Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time. Start multiple requests by calling fetch functions, then await them with Promise.all(). Requests begin as soon as fetch is called, not when you await.
Parallel data fetching example
Call getArtist(username) and getAlbums(username) without await to start both requests immediately. Then use const [artist, albums] = await Promise.all([artistData, albumsData]) to wait for both to resolve.
Promise.allSettled for error handling
If one request fails when using Promise.all, the entire operation will fail. Use Promise.allSettled() method instead to handle individual request failures without failing the entire operation.
refresh() function revalidates current page after mutation
After a mutation, call refresh() from 'next/cache' in a Server Action to refresh the client router and ensure the UI reflects the latest state. The refresh() function does not revalidate tagged data; use updateTag() or revalidateTag() instead for tagged data.
revalidatePath and revalidateTag after mutations
After performing a mutation, call revalidatePath() or revalidateTag() within the Server Function to revalidate the Next.js cache and show updated data.
Example: Revalidate cache after mutation
This example shows how to use revalidatePath to refresh cached data after a mutation:
```ts
'use server'
import { auth } from '@/lib/auth'
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
const session = await auth()
if (!session?.user) {
throw new Error('Unauthorized')
}
// Mutate data
// ...
revalidatePath('/posts')
}
```
Memoizing data requests with React cache to avoid duplicates
When the same data is needed for both metadata and page rendering, use React's cache function to memoize the return value and ensure the data is fetched only once. This prevents duplicate requests when both generateMetadata and the page component need the same data.
Passing runtime values to cached functions
You can extract values from runtime APIs and pass them as arguments to cached functions. This allows the cached function to be included in the prefetched content. Example: a non-cached component reads runtime data like `session` from cookies, then passes it to a cached component that receives it as a prop, making the sessionId part of the cache key.
Passing runtime values example
Example: `async function ProfileContent() { const session = (await cookies()).get('session')?.value; return <CachedContent sessionId={session} />; } async function CachedContent({ sessionId }: { sessionId: string }) { 'use cache'; const data = await fetchUserData(sessionId); return <div>{data}</div>; }`
Reading local resources at module scope
Some asynchronous APIs read local resources that don't depend on the incoming request, such as fonts or configuration files. When those resources are expected to be the same for every request, read them once at module scope instead of during rendering to avoid treating them as uncached data.
App Shell with unknown dynamic params
When dynamic params aren't known at build time, the reusable, URL-independent version is the App Shell: the same static shell with the param-specific parts left behind their fallbacks. Incremental Static Regeneration fills in the concrete versions after the first visit.
Incremental Static Regeneration with generateStaticParams
In a route with dynamic param segments, `generateStaticParams` prerenders the URLs you list at build time. Any other URL is served the App Shell instantly, then upgraded in the background with its now-known params and cached for the next visitor.
Dynamic rendering definition
Dynamic rendering occurs when a component is rendered at request time rather than build time. A component becomes dynamic when it uses Request-time APIs.
Incremental Static Regeneration (ISR) definition
ISR is a technique that allows you to update static content without rebuilding the entire site. It enables you to use static generation on a per-page basis while revalidating pages in the background as traffic comes in. In Next.js, ISR is also known as Revalidation.
Prerendering definition
Prerendering occurs when a component is rendered at build time or in the background during revalidation. The result is HTML and RSC Payload, which can be cached and served from a CDN. Prerendering is the default for components that don't use Request-time APIs.
Request-time APIs list
Request-time APIs are functions that access request-specific data, causing a component to opt into dynamic rendering. These include: cookies() to access request cookies, headers() to access request headers, searchParams to access URL query parameters, and draftMode() to enable or check draft mode.
Optimistic update should restore previous browser value if write fails
An optimistic update should restore the previous browser value if the write fails. If the server read is not cached, there is no server tag to invalidate.
Invalidate cached server read after mutation to enable fresh data on next render
After a mutation, invalidate any cached server read that provided the initial data so the next render can read a fresh value.