Repository: vercel/next.js
Pull request #79200: Docs IA 2.0: Review fetching page and move examples
Author: login: delbaoliveira
Labels: name: Documentation
description: Related to Next.js' official documentation.
name: locked
name: created-by: Next.js DevEx team
description: PRs by the DX team.
Created: 2025-05-14T11:01:33Z | Merged: 2025-05-21T14:38:11Z

Part of: https://linear.app/vercel/issue/DOC-4639/ia-20-migrate-bya-pages
No redirects needed yet as the page hasn't been deleted. 


Diff:
diff --git a/docs/01-app/01-getting-started/09-fetching-data.mdx b/docs/01-app/01-getting-started/09-fetching-data.mdx
index 2e446d3ba152..9bbd0ceeff25 100644
--- a/docs/01-app/01-getting-started/09-fetching-data.mdx
+++ b/docs/01-app/01-getting-started/09-fetching-data.mdx
@@ -8,9 +8,11 @@ related:
   links:
     - app/api-reference/functions/fetch
     - app/api-reference/file-conventions/loading
+    - app/api-reference/config/next-config-js/logging
+    - app/api-reference/config/next-config-js/taint
 ---
 
-This page will walk you through how you can fetch data in [Server Components](#server-components) and [Client Components](#client-components). As well as how to [stream](#streaming) content that depends on data.
+This page will walk you through how you can fetch data in [Server and Client Components](/docs/app/getting-started/server-and-client-components), and how to [stream](#streaming) components that depend on data.
 
 ## Fetching data
 
@@ -53,6 +55,11 @@ export default async function Page() {
 }
 ```
 
+> **Good to know:**
+>
+> - `fetch` responses are not cached by default. However, Next.js will [prerender](/docs/app/getting-started/partial-prerendering#static-rendering) the route and the output will be cached for improved performance. If you'd like to opt into [dynamic rendering](/docs/app/getting-started/partial-prerendering#dynamic-rendering), use the `{ cache: 'no-store' }` option. See the [`fetch` API Reference](/docs/app/api-reference/functions/fetch).
+> - During development, you can log `fetch` calls for better visibility and debugging. See the [`logging` API reference](/docs/app/api-reference/config/next-config-js/logging).
+
 #### With an ORM or database
 
 Since Server Components are rendered on the server, you can safely make database queries using an ORM or database client. Turn your component into an asynchronous function, and await the call:
@@ -203,6 +210,7 @@ export default function BlogPage() {
 
 ```jsx filename="app/blog/page.js" switcher
 'use client'
+
 import useSWR from 'swr'
 
 const fetcher = (url) => fetch(url).then((r) => r.json())
@@ -352,3 +360,266 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together, for example, with [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all):
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher
+import Albums from './albums'
+
+async function getArtist(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({ params }) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+> **Good to know:** If one request fails when using `Promise.all`, the entire operation will fail. To handle this, you can use the [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) method instead.
+
+### Preloading data
+
+You can preload data by creating an utility function that you eagerly call above blocking requests. `<Item>` conditionally renders based on the `checkIsAvailable()` function.
+
+You can call `preload()` before `checkIsAvailable()` to eagerly initiate `<Item/>` data dependencies. By the time `<Item/>` is rendered, its data has already been fetched.
+
+```tsx filename="app/item/[id]/page.tsx" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ id: string }>
+}) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id: string) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }: { id: string }) {
+  const result = await getItem(id)
+  // ...
+}
+```
+
+```jsx filename="app/item/[id]/page.js" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({ params }) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }) {
+  const result = await getItem(id)
+  // ...
+```
+
+Additionally, you can use React's [`cache` function](https://react.dev/reference/react/cache) and the [`server-only` package](https://www.npmjs.com/package/server-only) to create a reusable utility function. This approach allows you to cache the data fetching function and ensure that it's only executed on the server.
+
+```ts filename="utils/get-item.ts" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id: string) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id: string) => {
+  // ...
+})
+```
+
+```js filename="utils/get-item.js" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id) => {
+  // ...
+})
+```
diff --git a/docs/01-app/02-guides/index.mdx b/docs/01-app/02-guides/index.mdx
index be9b56244a04..8a423f4c360c 100644
--- a/docs/01-app/02-guides/index.mdx
+++ b/docs/01-app/02-guides/index.mdx
@@ -5,8 +5,8 @@ description: Learn how to implement common UI patterns and use cases using Next.
 
 ### Data Fetching
 
-- [Using the `fetch` API](/docs/app/building-your-application/data-fetching/fetching#fetching-data-on-the-server-with-the-fetch-api)
-- [Using an ORM or database client](/docs/app/building-your-application/data-fetching/fetching#fetching-data-on-the-server-with-an-orm-or-database)
+- [Using the `fetch` API](/docs/app/getting-started/fetching-data#with-the-fetch-api)
+- [Using an ORM or database client](/docs/app/getting-started/fetching-data#with-an-orm-or-database)
 - [Reading search params on the server](/docs/app/api-reference/file-conventions/page)
 - [Reading search params on the client](/docs/app/api-reference/functions/use-search-params)
 
diff --git a/docs/01-app/02-guides/production-checklist.mdx b/docs/01-app/02-guides/production-checklist.mdx
index a84666ea45ab..290684a346b1 100644
--- a/docs/01-app/02-guides/production-checklist.mdx
+++ b/docs/01-app/02-guides/production-checklist.mdx
@@ -64,7 +64,7 @@ While building your application, we recommend using the following features to en
 - **[Server Components](/docs/app/building-your-application/data-fetching/fetching):** Leverage the benefits of fetching data on the server using Server Components.
 - **[Route Handlers](/docs/app/building-your-application/routing/route-handlers):** Use Route Handlers to access your backend resources from Client Components. But do not call Route Handlers from Server Components to avoid an additional server request.
 - **[Streaming](/docs/app/building-your-application/routing/loading-ui-and-streaming):** Use Loading UI and React Suspense to progressively send UI from the server to the client, and prevent the whole route from blocking while data is being fetched.
-- **[Parallel Data Fetching](/docs/app/building-your-application/data-fetching/fetching#parallel-and-sequential-data-fetching):** Reduce network waterfalls by fetching data in parallel, where appropriate. Also, consider [preloading data](/docs/app/building-your-application/data-fetching/fetching#preloading-data) where appropriate.
+- **[Parallel Data Fetching](/docs/app/getting-started/fetching-data#parallel-data-fetching):** Reduce network waterfalls by fetching data in parallel, where appropriate. Also, consider [preloading data](/docs/app/getting-started/fetching-data#preloading-data) where appropriate.
 - **[Data Caching](/docs/app/deep-dive/caching#data-cache):** Verify whether your data requests are being cached or not, and opt into caching, where appropriate. Ensure requests that don't use `fetch` are [cached](/docs/app/api-reference/functions/unstable_cache).
 - **[Static Images](/docs/app/api-reference/file-conventions/public-folder):** Use the `public` directory to automatically cache your application's static assets, e.g. images.
 
@@ -96,7 +96,7 @@ While building your application, we recommend using the following features to en
 
 <AppOnly>
 
-- **[Tainting](/docs/app/building-your-application/data-fetching/fetching#preventing-sensitive-data-from-being-exposed-to-the-client):** Prevent sensitive data from being exposed to the client by tainting data objects and/or specific values.
+- **[Tainting](/docs/app/api-reference/config/next-config-js/taint):** Prevent sensitive data from being exposed to the client by tainting data objects and/or specific values.
 - **[Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations#authentication-and-authorization):** Ensure users are authorized to call Server Actions. Review the recommended [security practices](/blog/security-nextjs-server-components-actions).
 
 </AppOnly>
diff --git a/docs/01-app/03-building-your-application/02-data-fetching/01-fetching.mdx b/docs/01-app/03-building-your-application/02-data-fetching/01-fetching.mdx
index daef70af66bd..5f80df24350e 100644
--- a/docs/01-app/03-building-your-application/02-data-fetching/01-fetching.mdx
+++ b/docs/01-app/03-building-your-application/02-data-fetching/01-fetching.mdx
@@ -53,158 +53,6 @@ This example demonstrates a basic server-side data fetch using the `fetch` API i
 - React [`cache`](https://react.dev/reference/react/cache)
 - Next.js [`unstable_cache`](/docs/app/api-reference/functions/unstable_cache)
 
-## Examples
-
-### Fetching data on the server with the `fetch` API
-
-This component will fetch and display a list of blog posts. The response from `fetch` is not cached by default.
-
-```tsx filename="app/page.tsx" switcher
-export default async function Page() {
-  const data = await fetch('https://api.vercel.app/blog')
-  const posts = await data.json()
-  return (
-    <ul>
-      {posts.map((post) => (
-        <li key={post.id}>{post.title}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-```jsx filename="app/page.js" switcher
-export default async function Page() {
-  const data = await fetch('https://api.vercel.app/blog')
-  const posts = await data.json()
-  return (
-    <ul>
-      {posts.map((post) => (
-        <li key={post.id}>{post.title}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-If you are not using any [Dynamic APIs](/docs/app/getting-started/partial-prerendering#dynamic-rendering) anywhere else in this route, it will be prerendered during `next build` to a static page. The data can then be updated using [Incremental Static Regeneration](/docs/app/guides/incremental-static-regeneration).
-
-To prevent the page from prerendering, you can add the following to your file:
-
-```js
-export const dynamic = 'force-dynamic'
-```
-
-However, you will commonly use functions like `cookies`, `headers`, or reading the incoming `searchParams` from the page props, which will automatically make the page render dynamically. In this case, you do _not_ need to explicitly use `force-dynamic`.
-
-### Fetching data on the server with an ORM or database
-
-This component will fetch and display a list of blog posts. The response from the database is not cached by default but could be with [additional configuration](#caching-data-with-an-orm-or-database).
-
-```tsx filename="app/page.tsx" switcher
-import { db, posts } from '@/lib/db'
-
-export default async function Page() {
-  const allPosts = await db.select().from(posts)
-  return (
-    <ul>
-      {allPosts.map((post) => (
-        <li key={post.id}>{post.title}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-```jsx filename="app/page.js" switcher
-import { db, posts } from '@/lib/db'
-
-export default async function Page() {
-  const allPosts = await db.select().from(posts)
-  return (
-    <ul>
-      {allPosts.map((post) => (
-        <li key={post.id}>{post.title}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-If you are not using any [Dynamic APIs](/docs/app/getting-started/partial-prerendering#dynamic-rendering) anywhere else in this route, it will be prerendered during `next build` to a static page. The data can then be updated using [Incremental Static Regeneration](/docs/app/guides/incremental-static-regeneration).
-
-To prevent the page from prerendering, you can add the following to your file:
-
-```js
-export const dynamic = 'force-dynamic'
-```
-
-However, you will commonly use functions like `cookies`, `headers`, or reading the incoming `searchParams` from the page props, which will automatically make the page render dynamically. In this case, you do _not_ need to explicitly use `force-dynamic`.
-
-### Fetching data on the client
-
-We recommend first attempting to fetch data on the server-side.
-
-However, there are still cases where client-side data fetching makes sense. In these scenarios, you can manually call `fetch` in a `useEffect` (not recommended), or lean on popular React libraries in the community (such as [SWR](https://swr.vercel.app/) or [React Query](https://tanstack.com/query/latest)) for client fetching.
-
-```tsx filename="app/page.tsx" switcher
-'use client'
-
-import { useState, useEffect } from 'react'
-
-export function Posts() {
-  const [posts, setPosts] = useState(null)
-
-  useEffect(() => {
-    async function fetchPosts() {
-      const res = await fetch('https://api.vercel.app/blog')
-      const data = await res.json()
-      setPosts(data)
-    }
-    fetchPosts()
-  }, [])
-
-  if (!posts) return <div>Loading...</div>
-
-  return (
-    <ul>
-      {posts.map((post) => (
-        <li key={post.id}>{post.title}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-```jsx filename="app/page.js" switcher
-'use client'
-
-import { useState, useEffect } from 'react'
-
-export function Posts() {
-  const [posts, setPosts] = useState(null)
-
-  useEffect(() => {
-    async function fetchPosts() {
-      const res = await fetch('https://api.vercel.app/blog')
-      const data = await res.json()
-      setPosts(data)
-    }
-    fetchPosts()
-  }, [])
-
-  if (!posts) return <div>Loading...</div>
-
-  return (
-    <ul>
-      {posts.map((post) => (
-        <li key={post.id}>{post.title}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
 ### Caching data with an ORM or Database
 
 You can use the `unstable_cache` API to cache the response when running `next build`.
@@ -390,369 +238,4 @@ export const getPost = cache(async (id) => {
 
 ### Revalidating cached data
 
-Learn more about revalidating cached data with [Incremental Static Regeneration](/docs/app/guides/incremental-static-regeneration).
-
-## Patterns
-
-### Parallel and sequential data fetching
-
-When fetching data inside components, you need to be aware of two data fetching patterns: Parallel and Sequential.
-
-<Image
-  alt="Sequential and Parallel Data Fetching"
-  srcLight="/docs/light/sequential-parallel-data-fetching.png"
-  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
-  width="1600"
-  height="525"
-/>
-
-- **Sequential**: requests in a component tree are dependent on each other. This can lead to longer loading times.
-- **Parallel**: requests in a route are eagerly initiated and will load data at the same time. This reduces the total time it takes to load data.
-
-#### Sequential data fetching
-
-If you have nested components, and each component fetches its own data, then data fetching will happen sequentially if those data requests are not [memoized](/docs/app/deep-dive/caching#request-memoization).
-
-There may be cases where you want this pattern because one fetch depends on the result of the other. For example, the `Playlists` component will only start fetching data once the `Artist` component has finished fetching data because `Playlists` depends on the `artistID` prop:
-
-```tsx filename="app/artist/[username]/page.tsx" switcher
-export default async function Page({
-  params,
-}: {
-  params: Promise<{ username: string }>
-}) {
-  const { username } = await params
-  // Get artist information
-  const artist = await getArtist(username)
-
-  return (
-    <>
-      <h1>{artist.name}</h1>
-      {/* Show fallback UI while the Playlists component is loading */}
-      <Suspense fallback={<div>Loading...</div>}>
-        {/* Pass the artist ID to the Playlists component */}
-        <Playlists artistID={artist.id} />
-      </Suspense>
-    </>
-  )
-}
-
-async function Playlists({ artistID }: { artistID: string }) {
-  // Use the artist ID to fetch playlists
-  const playlists = await getArtistPlaylists(artistID)
-
-  return (
-    <ul>
-      {playlists.map((playlist) => (
-        <li key={playlist.id}>{playlist.name}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-```jsx filename="app/artist/[username]/page.js" switcher
-export default async function Page({ params }) {
-  const { username } = await params
-  // Get artist information
-  const artist = await getArtist(username)
-
-  return (
-    <>
-      <h1>{artist.name}</h1>
-      {/* Show fallback UI while the Playlists component is loading */}
-      <Suspense fallback={<div>Loading...</div>}>
-        {/* Pass the artist ID to the Playlists component */}
-        <Playlists artistID={artist.id} />
-      </Suspense>
-    </>
-  )
-}
-
-async function Playlists({ artistID }) {
-  // Use the artist ID to fetch playlists
-  const playlists = await getArtistPlaylists(artistID)
-
-  return (
-    <ul>
-      {playlists.map((playlist) => (
-        <li key={playlist.id}>{playlist.name}</li>
-      ))}
-    </ul>
-  )
-}
-```
-
-You can use [`loading.js`](/docs/app/building-your-application/routing/loading-ui-and-streaming) (for route segments) or [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) (for nested components) to show an instant loading state while React streams in the result.
-
-This will prevent the whole route from being blocked by data requests, and the user will be able to interact with the parts of the page that are ready.
-
-#### Parallel Data Fetching
-
-By default, layout and page segments are rendered in parallel. This means requests will be initiated in parallel.
-
-However, due to the nature of `async`/`await`, an awaited request inside the same segment or component will block any requests below it.
-
-To fetch data in parallel, you can eagerly initiate requests by defining them outside the components that use the data. This saves time by initiating both requests in parallel, however, the user won't see the rendered result until both promises are resolved.
-
-In the example below, the `getArtist` and `getAlbums` functions are defined outside the `Page` component and initiated inside the component using `Promise.all`:
-
-```tsx filename="app/artist/[username]/page.tsx" switcher
-import Albums from './albums'
-
-async function getArtist(username: string) {
-  const res = await fetch(`https://api.example.com/artist/${username}`)
-  return res.json()
-}
-
-async function getAlbums(username: string) {
-  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
-  return res.json()
-}
-
-export default async function Page({
-  params,
-}: {
-  params: Promise<{ username: string }>
-}) {
-  const { username } = await params
-  const artistData = getArtist(username)
-  const albumsData = getAlbums(username)
-
-  // Initiate both requests in parallel
-  const [artist, albums] = await Promise.all([artistData, albumsData])
-
-  return (
-    <>
-      <h1>{artist.name}</h1>
-      <Albums list={albums} />
-    </>
-  )
-}
-```
-
-```jsx filename="app/artist/[username]/page.js" switcher
-import Albums from './albums'
-
-async function getArtist(username) {
-  const res = await fetch(`https://api.example.com/artist/${username}`)
-  return res.json()
-}
-
-async function getAlbums(username) {
-  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
-  return res.json()
-}
-
-export default async function Page({ params }) {
-  const { username } = await params
-  const artistData = getArtist(username)
-  const albumsData = getAlbums(username)
-
-  // Initiate both requests in parallel
-  const [artist, albums] = await Promise.all([artistData, albumsData])
-
-  return (
-    <>
-      <h1>{artist.name}</h1>
-      <Albums list={albums} />
-    </>
-  )
-}
-```
-
-In addition, you can add a [Suspense Boundary](/docs/app/building-your-application/routing/loading-ui-and-streaming) to break up the rendering work and show part of the result as soon as possible.
-
-### Preloading Data
-
-Another way to prevent waterfalls is to use the _preload_ pattern by creating an utility function that you eagerly call above blocking requests. For example, `checkIsAvailable()` blocks `<Item/>` from rendering, so you can call `preload()` before it to eagerly initiate `<Item/>` data dependencies. By the time `<Item/>` is rendered, its data has already been fetched.
-
-Note that `preload` function doesn't block `checkIsAvailable()` from running.
-
-```tsx filename="components/Item.tsx" switcher
-import { getItem } from '@/utils/get-item'
-
-export const preload = (id: string) => {
-  // void evaluates the given expression and returns undefined
-  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
-  void getItem(id)
-}
-export default async function Item({ id }: { id: string }) {
-  const result = await getItem(id)
-  // ...
-}
-```
-
-```jsx filename="components/Item.js" switcher
-import { getItem } from '@/utils/get-item'
-
-export const preload = (id) => {
-  // void evaluates the given expression and returns undefined
-  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
-  void getItem(id)
-}
-export default async function Item({ id }) {
-  const result = await getItem(id)
-  // ...
-}
-```
-
-```tsx filename="app/item/[id]/page.tsx" switcher
-import Item, { preload, checkIsAvailable } from '@/components/Item'
-
-export default async function Page({
-  params,
-}: {
-  params: Promise<{ id: string }>
-}) {
-  const { id } = await params
-  // starting loading item data
-  preload(id)
-  // perform another asynchronous task
-  const isAvailable = await checkIsAvailable()
-
-  return isAvailable ? <Item id={id} /> : null
-}
-```
-
-```jsx filename="app/item/[id]/page.js" switcher
-import Item, { preload, checkIsAvailable } from '@/components/Item'
-
-export default async function Page({ params }) {
-  const { id } = await params
-  // starting loading item data
-  preload(id)
-  // perform another asynchronous task
-  const isAvailable = await checkIsAvailable()
-
-  return isAvailable ? <Item id={id} /> : null
-}
-```
-
-> **Good to know:** The "preload" function can also have any name as it's a pattern, not an API.
-
-#### Using React `cache` and `server-only` with the Preload Pattern
-
-You can combine the `cache` function, the `preload` pattern, and the `server-only` package to create a data fetching utility that can be used throughout your app.
-
-```ts filename="utils/get-item.ts" switcher
-import { cache } from 'react'
-import 'server-only'
-
-export const preload = (id: string) => {
-  void getItem(id)
-}
-
-export const getItem = cache(async (id: string) => {
-  // ...
-})
-```
-
-```js filename="utils/get-item.js" switcher
-import { cache } from 'react'
-import 'server-only'
-
-export const preload = (id) => {
-  void getItem(id)
-}
-
-export const getItem = cache(async (id) => {
-  // ...
-})
-```
-
-With this approach, you can eagerly fetch data, cache responses, and guarantee that this data fetching [only happens on the server](/docs/app/getting-started/server-and-client-components#examples#keeping-server-only-code-out-of-the-client-environment).
-
-The `utils/get-item` exports can be used by Layouts, Pages, or other components to give them control over when an item's data is fetched.
-
-> **Good to know:**
->
-> - We recommend using the [`server-only` package](/docs/app/getting-started/server-and-client-components#examples#keeping-server-only-code-out-of-the-client-environment) to make sure server data fetching functions are never used on the client.
-
-### Preventing sensitive data from being exposed to the client
-
-We recommend using React's taint APIs, [`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference) and [`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue), to prevent whole object instances or sensitive values from being passed to the client.
-
-To enable tainting in your application, set the Next.js Config `experimental.taint` option to `true`:
-
-```js filename="next.config.js"
-module.exports = {
-  experimental: {
-    taint: true,
-  },
-}
-```
-
-Then pass the object or value you want to taint to the `experimental_taintObjectReference` or `experimental_taintUniqueValue` functions:
-
-```ts filename="app/utils.ts" switcher
-import { queryDataFromDB } from './api'
-import {
-  experimental_taintObjectReference,
-  experimental_taintUniqueValue,
-} from 'react'
-
-export async function getUserData() {
-  const data = await queryDataFromDB()
-  experimental_taintObjectReference(
-    'Do not pass the whole user object to the client',
-    data
-  )
-  experimental_taintUniqueValue(
-    "Do not pass the user's address to the client",
-    data,
-    data.address
-  )
-  return data
-}
-```
-
-```js filename="app/utils.js" switcher
-import { queryDataFromDB } from './api'
-import {
-  experimental_taintObjectReference,
-  experimental_taintUniqueValue,
-} from 'react'
-
-export async function getUserData() {
-  const data = await queryDataFromDB()
-  experimental_taintObjectReference(
-    'Do not pass the whole user object to the client',
-    data
-  )
-  experimental_taintUniqueValue(
-    "Do not pass the user's address to the client",
-    data,
-    data.address
-  )
-  return data
-}
-```
-
-```tsx filename="app/page.tsx" switcher
-import { getUserData } from './data'
-
-export async function Page() {
-  const userData = getUserData()
-  return (
-    <ClientComponent
-      user={userData} // this will cause an error because of taintObjectReference
-      address={userData.address} // this will cause an error because of taintUniqueValue
-    />
-  )
-}
-```
-
-```jsx filename="app/page.js" switcher
-import { getUserData } from './data'
-
-export async function Page() {
-  const userData = await getUserData()
-  return (
-    <ClientComponent
-      user={userData} // this will cause an error because of taintObjectReference
-      address={userData.address} // this will cause an error because of taintUniqueValue
-    />
-  )
-}
-```
+Learn more about revalidating cached data with [Incremental Static Regeneration](/docs/app/building-your-application/data-fetching/incremental-static-regeneration).
diff --git a/docs/01-app/03-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx b/docs/01-app/03-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx
index d3bccbd789ad..9ab7fb73dc88 100644
--- a/docs/01-app/03-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx
+++ b/docs/01-app/03-building-your-application/02-data-fetching/03-server-actions-and-mutations.mdx
@@ -973,7 +973,7 @@ Closures are useful when you need to capture a _snapshot_ of data (e.g. `publish
 
 However, for this to happen, the captured variables are sent to the client and back to the server when the action is invoked. To prevent sensitive data from being exposed to the client, Next.js automatically encrypts the closed-over variables. A new private key is generated for each action every time a Next.js application is built. This means actions can only be invoked for a specific build.
 
-> **Good to know:** We don't recommend relying on encryption alone to prevent sensitive values from being exposed on the client. Instead, you should use the [React taint APIs](/docs/app/building-your-application/data-fetching/fetching#preventing-sensitive-data-from-being-exposed-to-the-client) to proactively prevent specific data from being sent to the client.
+> **Good to know:** We don't recommend relying on encryption alone to prevent sensitive values from being exposed on the client. Instead, you should use the [React taint APIs](/docs/app/api-reference/config/next-config-js/taint) to proactively prevent specific data from being sent to the client.
 
 ### Overwriting encryption keys (advanced)
 


Reviews:
user: login: leerob
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:10:32Z
user: login: delbaoliveira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:26:19Z
user: login: icyJoseph
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T18:47:30Z
user: login: Hardanish-Singh
state: APPROVED
author_association: NONE
submitted_at: 2025-05-15T18:55:22Z
user: login: icyJoseph
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T19:49:31Z
user: login: delbaoliveira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T08:30:44Z
user: login: delbaoliveira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T08:36:44Z
user: login: icyJoseph
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T09:53:32Z
user: login: delbaoliveira
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T12:58:08Z
user: login: icyJoseph
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-21T09:33:30Z

Review comments:
diff_hunk: @@ -352,3 +355,365 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together with `Promise.all`:
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher
+import Albums from './albums'
+
+async function getArtist(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({ params }) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+### Preloading data
+
+You can preload data by creating an utility function that you eagerly call above blocking requests. `<Item>` conditionally renders based on the `checkIsAvailable()` function.
+
+You can call `preload()` before `checkIsAvailable()` to eagerly initiate `<Item/>` data dependencies. By the time `<Item/>` is rendered, its data has already been fetched.
+
+```tsx filename="app/item/[id]/page.tsx" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ id: string }>
+}) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id: string) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }: { id: string }) {
+  const result = await getItem(id)
+  // ...
+}
+```
+
+```jsx filename="app/item/[id]/page.js" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({ params }) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }) {
+  const result = await getItem(id)
+  // ...
+```
+
+Additionally, you can use React's [`cache` function](https://react.dev/reference/react/cache) and the [`server-only` package](https://www.npmjs.com/package/server-only) to create a reusable utility function. This approach allows you to cache the data fetching function and ensure that it's only executed on the server.
+
+```ts filename="utils/get-item.ts" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id: string) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id: string) => {
+  // ...
+})
+```
+
+```js filename="utils/get-item.js" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id) => {
+  // ...
+})
+```
+
+### Tainting data
+
+You can use React's taint APIs, [`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference) and [`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue), to prevent whole data objects or sensitive values from being passed to the client.
+
+To enable tainting in your application, set the Next.js Config `experimental.taint` option to `true`:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+  experimental: {
+    taint: true,
+  },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+/** @type {import('next').NextConfig} */
+module.exports = {
+  experimental: {
+    taint: true,
+  },
+}
+```
+
+Then, pass the object or value you want to taint to the `experimental_taintObjectReference` or `experimental_taintUniqueValue` functions:
+
+```ts filename="app/utils.ts" switcher
+import { queryDataFromDB } from './api'
+import {
+  experimental_taintObjectReference,
+  experimental_taintUniqueValue,
+} from 'react'
+
+export async function getUserData() {
+  const data = await queryDataFromDB()
+  experimental_taintObjectReference(
+    'Do not pass the whole user object to the client',
+    data
+  )
+  experimental_taintUniqueValue(
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: leerob
body: This is probably more for a deep dive than getting started. Thoughts?
created_at: 2025-05-15T17:10:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -352,3 +355,365 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together with `Promise.all`:
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher
+import Albums from './albums'
+
+async function getArtist(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({ params }) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+### Preloading data
+
+You can preload data by creating an utility function that you eagerly call above blocking requests. `<Item>` conditionally renders based on the `checkIsAvailable()` function.
+
+You can call `preload()` before `checkIsAvailable()` to eagerly initiate `<Item/>` data dependencies. By the time `<Item/>` is rendered, its data has already been fetched.
+
+```tsx filename="app/item/[id]/page.tsx" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ id: string }>
+}) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id: string) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }: { id: string }) {
+  const result = await getItem(id)
+  // ...
+}
+```
+
+```jsx filename="app/item/[id]/page.js" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({ params }) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }) {
+  const result = await getItem(id)
+  // ...
+```
+
+Additionally, you can use React's [`cache` function](https://react.dev/reference/react/cache) and the [`server-only` package](https://www.npmjs.com/package/server-only) to create a reusable utility function. This approach allows you to cache the data fetching function and ensure that it's only executed on the server.
+
+```ts filename="utils/get-item.ts" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id: string) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id: string) => {
+  // ...
+})
+```
+
+```js filename="utils/get-item.js" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id) => {
+  // ...
+})
+```
+
+### Tainting data
+
+You can use React's taint APIs, [`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference) and [`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue), to prevent whole data objects or sensitive values from being passed to the client.
+
+To enable tainting in your application, set the Next.js Config `experimental.taint` option to `true`:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+  experimental: {
+    taint: true,
+  },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+/** @type {import('next').NextConfig} */
+module.exports = {
+  experimental: {
+    taint: true,
+  },
+}
+```
+
+Then, pass the object or value you want to taint to the `experimental_taintObjectReference` or `experimental_taintUniqueValue` functions:
+
+```ts filename="app/utils.ts" switcher
+import { queryDataFromDB } from './api'
+import {
+  experimental_taintObjectReference,
+  experimental_taintUniqueValue,
+} from 'react'
+
+export async function getUserData() {
+  const data = await queryDataFromDB()
+  experimental_taintObjectReference(
+    'Do not pass the whole user object to the client',
+    data
+  )
+  experimental_taintUniqueValue(
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: delbaoliveira
body: Yes, it does feel like non-essential knowledge. Maybe something for the `experimental.taint` API reference? 
https://linear.app/vercel/issue/DOC-4668/document-the-experimentaltaint-option-in-nextconfigts
created_at: 2025-05-15T17:26:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -53,6 +53,8 @@ export default async function Page() {
 }
 ```
 
+> **Good to know:** `fetch` responses are not cached by default. However, Next.js will [prerender](/docs/app/getting-started/partial-prerendering#static-rendering) the route and the output will be cached for improved performance. If you'd like to opt into [dynamic rendering](/docs/app/getting-started/partial-prerendering#dynamic-rendering), use the `{ cache: 'no-store' }` option. See the [`fetch` API Reference](/docs/app/api-reference/functions/fetch).
+
 #### With an ORM or database
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: icyJoseph
body: Should we mention that one can activate, https://nextjs.org/docs/app/api-reference/config/next-config-js/logging, to see if a fetch call is skips or hits cache?
created_at: 2025-05-15T18:47:30Z
author_association: MEMBER
diff_hunk: @@ -352,3 +355,365 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together with `Promise.all`:
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: icyJoseph
body: Maybe a `Good to know` is due here. `Promise.all` rejects, if one of the promises rejects. That might not be desirable. We should hint at the possibility of using `Promise.allSettled`.
created_at: 2025-05-15T19:49:30Z
author_association: MEMBER
diff_hunk: @@ -53,6 +53,8 @@ export default async function Page() {
 }
 ```
 
+> **Good to know:** `fetch` responses are not cached by default. However, Next.js will [prerender](/docs/app/getting-started/partial-prerendering#static-rendering) the route and the output will be cached for improved performance. If you'd like to opt into [dynamic rendering](/docs/app/getting-started/partial-prerendering#dynamic-rendering), use the `{ cache: 'no-store' }` option. See the [`fetch` API Reference](/docs/app/api-reference/functions/fetch).
+
 #### With an ORM or database
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: delbaoliveira
body: Good suggestion 👍🏼 
created_at: 2025-05-16T08:30:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -352,3 +355,365 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together with `Promise.all`:
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: delbaoliveira
body: Yes 🙌🏼 
created_at: 2025-05-16T08:36:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -352,3 +355,365 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together with `Promise.all`:
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher
+import Albums from './albums'
+
+async function getArtist(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({ params }) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+### Preloading data
+
+You can preload data by creating an utility function that you eagerly call above blocking requests. `<Item>` conditionally renders based on the `checkIsAvailable()` function.
+
+You can call `preload()` before `checkIsAvailable()` to eagerly initiate `<Item/>` data dependencies. By the time `<Item/>` is rendered, its data has already been fetched.
+
+```tsx filename="app/item/[id]/page.tsx" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ id: string }>
+}) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id: string) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }: { id: string }) {
+  const result = await getItem(id)
+  // ...
+}
+```
+
+```jsx filename="app/item/[id]/page.js" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({ params }) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }) {
+  const result = await getItem(id)
+  // ...
+```
+
+Additionally, you can use React's [`cache` function](https://react.dev/reference/react/cache) and the [`server-only` package](https://www.npmjs.com/package/server-only) to create a reusable utility function. This approach allows you to cache the data fetching function and ensure that it's only executed on the server.
+
+```ts filename="utils/get-item.ts" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id: string) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id: string) => {
+  // ...
+})
+```
+
+```js filename="utils/get-item.js" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id) => {
+  // ...
+})
+```
+
+### Tainting data
+
+You can use React's taint APIs, [`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference) and [`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue), to prevent whole data objects or sensitive values from being passed to the client.
+
+To enable tainting in your application, set the Next.js Config `experimental.taint` option to `true`:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+  experimental: {
+    taint: true,
+  },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+/** @type {import('next').NextConfig} */
+module.exports = {
+  experimental: {
+    taint: true,
+  },
+}
+```
+
+Then, pass the object or value you want to taint to the `experimental_taintObjectReference` or `experimental_taintUniqueValue` functions:
+
+```ts filename="app/utils.ts" switcher
+import { queryDataFromDB } from './api'
+import {
+  experimental_taintObjectReference,
+  experimental_taintUniqueValue,
+} from 'react'
+
+export async function getUserData() {
+  const data = await queryDataFromDB()
+  experimental_taintObjectReference(
+    'Do not pass the whole user object to the client',
+    data
+  )
+  experimental_taintUniqueValue(
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: icyJoseph
body: The `experimenta.taint` API is almost ready, so we can probably reduce the amount of info on this section
created_at: 2025-05-19T09:53:32Z
author_association: MEMBER
diff_hunk: @@ -352,3 +355,365 @@ export default function BlogPage() {
 An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
 
 In development, you can preview and inspect the loading state of your components using the [React Devtools](https://react.dev/learn/react-developer-tools).
+
+## Examples
+
+### Sequential data fetching
+
+Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are not [deduplicated](/docs/app/deep-dive/caching#request-memoization), leading to longer response times.
+
+<Image
+  alt="Sequential and Parallel Data Fetching"
+  srcLight="/docs/light/sequential-parallel-data-fetching.png"
+  srcDark="/docs/dark/sequential-parallel-data-fetching.png"
+  width="1600"
+  height="525"
+/>
+
+There may be cases where you want this pattern because one fetch depends on the result of the other.
+
+For example, the `<Playlists>` component will only start fetching data once the `<Artist>` component has finished fetching data because `<Playlists>` depends on the `artistID` prop:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }: { artistID: string }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" switcher
+export default async function Page({ params }) {
+  const { username } = await params
+  // Get artist information
+  const artist = await getArtist(username)
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      {/* Show fallback UI while the Playlists component is loading */}
+      <Suspense fallback={<div>Loading...</div>}>
+        {/* Pass the artist ID to the Playlists component */}
+        <Playlists artistID={artist.id} />
+      </Suspense>
+    </>
+  )
+}
+
+async function Playlists({ artistID }) {
+  // Use the artist ID to fetch playlists
+  const playlists = await getArtistPlaylists(artistID)
+
+  return (
+    <ul>
+      {playlists.map((playlist) => (
+        <li key={playlist.id}>{playlist.name}</li>
+      ))}
+    </ul>
+  )
+}
+```
+
+To improve the user experience, you should use [React `<Suspense>`](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) to show a `fallback` while data is being fetch. This will enable [streaming](#streaming) and prevent the whole route from being blocked by the sequential data requests.
+
+### Parallel data fetching
+
+Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
+
+By default, [layouts and pages](/docs/app/getting-started/layouts-and-pages) are rendered in parallel. So each segment starts fetching data as soon as possible.
+
+However, within _any_ component, multiple `async`/`await` requests can still be sequential if placed after the other. For example, `getAlbums` will be blocked until `getArtist` is resolved:
+
+```tsx filename="app/artist/[username]/page.tsx" switcher
+import { getArtist, getAlbums } from '@/app/lib/data'
+
+export default async function Page({ params }) {
+  // These requests will be sequential
+  const { username } = await params
+  const artist = await getArtist(username)
+  const albums = await getAlbums(username)
+  return <div>{artist.name}</div>
+}
+```
+
+You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together with `Promise.all`:
+
+```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher
+import Albums from './albums'
+
+async function getArtist(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username: string) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ username: string }>
+}) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher
+import Albums from './albums'
+
+async function getArtist(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}`)
+  return res.json()
+}
+
+async function getAlbums(username) {
+  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
+  return res.json()
+}
+
+export default async function Page({ params }) {
+  const { username } = await params
+  const artistData = getArtist(username)
+  const albumsData = getAlbums(username)
+
+  // Initiate both requests in parallel
+  const [artist, albums] = await Promise.all([artistData, albumsData])
+
+  return (
+    <>
+      <h1>{artist.name}</h1>
+      <Albums list={albums} />
+    </>
+  )
+}
+```
+
+### Preloading data
+
+You can preload data by creating an utility function that you eagerly call above blocking requests. `<Item>` conditionally renders based on the `checkIsAvailable()` function.
+
+You can call `preload()` before `checkIsAvailable()` to eagerly initiate `<Item/>` data dependencies. By the time `<Item/>` is rendered, its data has already been fetched.
+
+```tsx filename="app/item/[id]/page.tsx" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({
+  params,
+}: {
+  params: Promise<{ id: string }>
+}) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id: string) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }: { id: string }) {
+  const result = await getItem(id)
+  // ...
+}
+```
+
+```jsx filename="app/item/[id]/page.js" switcher
+import { getItem } from '@/lib/data'
+
+export default async function Page({ params }) {
+  const { id } = await params
+  // starting loading item data
+  preload(id)
+  // perform another asynchronous task
+  const isAvailable = await checkIsAvailable()
+
+  return isAvailable ? <Item id={id} /> : null
+}
+
+export const preload = (id) => {
+  // void evaluates the given expression and returns undefined
+  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
+  void getItem(id)
+}
+export async function Item({ id }) {
+  const result = await getItem(id)
+  // ...
+```
+
+Additionally, you can use React's [`cache` function](https://react.dev/reference/react/cache) and the [`server-only` package](https://www.npmjs.com/package/server-only) to create a reusable utility function. This approach allows you to cache the data fetching function and ensure that it's only executed on the server.
+
+```ts filename="utils/get-item.ts" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id: string) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id: string) => {
+  // ...
+})
+```
+
+```js filename="utils/get-item.js" switcher
+import { cache } from 'react'
+import 'server-only'
+import { getItem } from '@/lib/data'
+
+export const preload = (id) => {
+  void getItem(id)
+}
+
+export const getItem = cache(async (id) => {
+  // ...
+})
+```
+
+### Tainting data
+
+You can use React's taint APIs, [`taintObjectReference`](https://react.dev/reference/react/experimental_taintObjectReference) and [`taintUniqueValue`](https://react.dev/reference/react/experimental_taintUniqueValue), to prevent whole data objects or sensitive values from being passed to the client.
+
+To enable tainting in your application, set the Next.js Config `experimental.taint` option to `true`:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+  experimental: {
+    taint: true,
+  },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+/** @type {import('next').NextConfig} */
+module.exports = {
+  experimental: {
+    taint: true,
+  },
+}
+```
+
+Then, pass the object or value you want to taint to the `experimental_taintObjectReference` or `experimental_taintUniqueValue` functions:
+
+```ts filename="app/utils.ts" switcher
+import { queryDataFromDB } from './api'
+import {
+  experimental_taintObjectReference,
+  experimental_taintUniqueValue,
+} from 'react'
+
+export async function getUserData() {
+  const data = await queryDataFromDB()
+  experimental_taintObjectReference(
+    'Do not pass the whole user object to the client',
+    data
+  )
+  experimental_taintUniqueValue(
path: docs/01-app/01-getting-started/09-fetching-data.mdx
user: login: delbaoliveira
body: Thank you! 
created_at: 2025-05-19T12:58:08Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-05-14T11:01:38Z
body: ###  ⚠️  No Changeset found

Latest commit: ae95816fca4e5af481621fc9ca7600ed5e047ecd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/vercel/next.js/new/docs-ia-data-fetching?filename=.changeset/shiny-lamps-cross.md&value=---%0A%0A---%0A%0ADocs%20IA%202.0%3A%20Review%20fetching%20page%20and%20move%20examples%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-14T11:01:52Z
body: <!-- LINK_CHECKER_COMMENT -->
Hi there :wave:

It looks like this PR introduces broken links to the docs, please take a moment to fix them before merging:

| Broken link | Type | File | 
| ----------- | ----------- | ----------- | 
| /docs/app/building-your-application/data-fetching/incremental-static-regeneration | link | [/docs/01-app/03-building-your-application/02-data-fetching/01-fetching.mdx](https://github.com/vercel/next.js/blob/ae95816fca4e5af481621fc9ca7600ed5e047ecd/docs/01-app/03-building-your-application/02-data-fetching/01-fetching.mdx) | 

Thank you :pray:
author_association: CONTRIBUTOR