Skip to main content

Nextjs Data Fetching

Nextjs data fetching.

Checklist

  1. The data requests are unintenionally blocking each other, creating a request waterfall.
  2. By default, Next.js prerenders routes to improve performance, this is called Static Rendering. So if your data changes, it won't be reflected in your dashboard.

Request Waterfalls

Request Waterfalls

Use when: needing to satisfy a condition before making the next request.

Pitfalls

  • The data requests are unintenionally blocking each other providing a bad user experience.

Solution:

  1. Execute all data fetches at the same time, which can lead to performance gains
  2. Use streaming
export async function fetchCardData() {
try {
const invoiceCountPromise = sql`SELECT COUNT(*) FROM invoices`;
const customerCountPromise = sql`SELECT COUNT(*) FROM customers`;
const invoiceStatusPromise = sql`SELECT
SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS "paid",
SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS "pending"
FROM invoices`;

const data = await Promise.all([
invoiceCountPromise,
customerCountPromise,
invoiceStatusPromise,
]);
// ...
}
}
note

With Promise.allSettled(), you can also return an array of objects with status and value keys, so can check a promise's status is fulfilled or rejected before passing the value to your component. It's useful if you want to handle errors more gracefully.

Dynamic Rendering

With Dynamic Rendering, content is rendered on the server for each user at request time (when the user visits the page). There are a couple of benefits of dynamic rendering:

  • Real-Time Data - Dynamic rendering allows your application to display real-time or frequently updated data. This is ideal for applications where data changes often.
  • User-Specific Content - It's easier to serve user-specific content, such as personalized dashboards or user profiles, through dynamic rendering, as the data is updated based on user interaction.
  • Request Time Information - Dynamic rendering allows you to access information that can only be known at request time, such as cookies or the URL's search params.

Suspense Boundaries

Where you place your suspense boundaries will vary depending on your application. such as:

  1. How you want the user to experience the page as it streams.
  2. What content you want to prioritize.
  3. If the components rely on data fetching.

Experiments and checks.

  1. Stream the whole page with loading.tsx... may lead to a longer loading time if one of the components has a slow data fetch.
  2. Stream every component individually... may lead to UI popping into the screen as it becomes ready.
  3. Create a staggered effect by streaming page sections by creating wrapper components.
tip

In general move data fetches down to the components that need it, and wrap those components in Suspense.