Fetching

Framework Next.js 13 Fetching

Fetching Data on the Server

Whenever possible, we recommend fetching data inside Server Components. Server Components always fetch data on the server. This allows you to:

  • Have direct access to backend data resources (e.g. databases).
  • Keep your application more secure by preventing sensitive information, such as access tokens and API keys, from being exposed to the client.
  • Fetch data and render in the same environment. This reduces both the back-and-forth communication between client and server, as well as the work on the main thread on the client.
  • Perform multiple data fetches with single round-trip instead of multiple individual requests on the client.
  • Reduce client-server waterfalls.
  • Depending on your region, data fetching can also happen closer to your data source, reducing latency and improving performance.

Fetching type

Static Data Fetching

By default, fetch will automatically fetch and cache data indefinitely.

fetch('https://...'); // cache: 'force-cache' is the default

Revalidating Data

To revalidate cached data at a timed interval, you can use the next.revalidate option in fetch() to set the cache lifetime of a resource (in seconds).

fetch('https://...', { next: { revalidate: 10 } });
See Revalidating Data for more information.

Dynamic Data Fetching

To fetch fresh data on every fetch request, use the cache: ’no-store’ option.

fetch('https://...', { cache: 'no-store' });

Blocking Rendering in a Route

In the app directory, you have additional options to explore:

  1. You can use loading.js to show an instant loading state from the server while streaming in the result from your data fetching function.
  2. You can move data fetching lower in the component tree to only block rendering for the parts of the page that need it. For example, moving data fetching to a specific component rather than fetching it at the root layout.

Whenever possible, it’s best to fetch data in the segment that uses it. This also allows you to show a loading state for only the part of the page that is loading, and not the entire page.

Segment Cache Configuration

Route Segment Config Options

// layout.js|page.js
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
export function generateStaticParams(...)

you can use segment configuration to customize the cache behavior of the entire segment.

// app/page.tsx
import prisma from './lib/prisma';

export const revalidate = 3600; // revalidate every hour

async function getPosts() {
  const posts = await prisma.post.findMany();
  return posts;
}

export default async function Page() {
  const posts = await getPosts();
  // ...
}

Data Fetching Patterns

Parallel Data Fetching

To minimize client-server waterfalls, we recommend this pattern to fetch data in parallel:

Wait for all requests

// app/artist/[username]/page.jsx
import Albums from './albums';

async function getArtist(username) {
  const res = await fetch(`https://api.example.com/artist/${username}`);
  return res.json();
}

async function getArtistAlbums(username) {
  const res = await fetch(`https://api.example.com/artist/${username}/albums`);
  return res.json();
}


export default async function Page({ params: { username } }) {
  // Initiate both requests in parallel
  const artistData = getArtist(username);
  const albumsData = getArtistAlbums(username);

  // Wait for the promises to resolve
  const [artist, albums] = await Promise.all([artistData, albumsData]);

  return (
    <>
      <h1>{artist.name}</h1>
      <Albums list={albums}></Albums>
    </>
  );
}

Wait for partial requests

export default async function Page({ params: { username } }) {
  // Initiate both requests in parallel
  const artistData = getArtist(username);
  const albumData = getArtistAlbums(username);

  // Wait for the artist's promise to resolve first
  const artist = await artistData;

  return (
    <>
      <h1>{artist.name}</h1>
      {/* Send the artist information first,
      and wrap albums in a suspense boundary */}
      <Suspense fallback={<div>Loading...</div>}>
        <Albums promise={albumData} />
      </Suspense>
    </>
  );
}

// Albums Component
async function Albums({ promise }) {
  // Wait for the albums promise to resolve
  const albums = await promise;

  return (
    <ul>
      {albums.map((album) => (
        <li key={album.id}>{album.name}</li>
      ))}
    </ul>
  );
}

API Routes

API routes should still be defined in the pages/api/* directory and NOT moved to the app directory.

API Routes

// pages/api/user.ts
import { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ name: 'John Doe' })
}

Reference


Cache

Framework Next.js 13 Fetching Cache

Axios

Framework Next.js 13 Fetching Axios