2.2K Views

NEXT106 - Data Fetching Basics

Learn how data fetching works in Next.js App Router, understand server-side data loading, caching behavior, and basic rendering strategies using the fetch API.

Data fetching is one of the areas where Next.js truly shines compared to plain React.
In this lesson, you will learn how data fetching works in the App Router and how to load data efficiently on the server.

Data Fetching in Next.js vs React

In a traditional React app:

  • Data is fetched on the client
  • UI renders first, then data loads
  • SEO and performance may suffer

In Next.js:

  • Data can be fetched on the server
  • HTML is generated with data included
  • Better SEO and faster first paint

This is a major architectural difference.


Server Components by Default

In the App Router, components are Server Components by default.

This means:

  • Code runs on the server
  • You can fetch data directly
  • Sensitive logic stays server-side
  • Smaller JavaScript bundles

Client-side interactivity is added only when needed.


Basic Data Fetching with fetch

Next.js uses the native fetch API for data fetching.

Example:

async function Page() {
  const response = await fetch("https://example.com/api/posts");
  const data = await response.json();
 
  return (
    <ul>
      {data.map(item => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  );
}
 
export default Page;

Data is fetched before rendering the page.


Async Components

Pages in the App Router can be async functions.

Benefits:

  • Cleaner code
  • No extra hooks needed
  • Data and UI live together

This pattern replaces useEffect-based fetching in many cases.


Caching Behavior

Next.js automatically caches fetch requests by default.

Default behavior:

  • Requests are cached
  • Results are reused
  • Improves performance

You can control caching behavior explicitly.


Disabling Cache (Dynamic Data)

For dynamic or frequently changing data, disable caching.

fetch("https://example.com/api/posts", {
  cache: "no-store"
});

This ensures fresh data on every request.


Revalidation (Static Data with Updates)

You can revalidate cached data at intervals.

fetch("https://example.com/api/posts", {
  next: { revalidate: 60 }
});

This updates the data every 60 seconds while keeping performance benefits.


Error Handling

Always handle failed requests.

const res = await fetch("https://example.com/api");
 
if (!res.ok) {
  throw new Error("Failed to fetch data");
}

Errors can be handled using error boundaries in Next.js.


Client-Side Fetching (When Needed)

Some data must be fetched on the client, such as:

  • User interactions
  • Auth-dependent data
  • Browser-only APIs

In such cases, mark the component as a client component.

"use client";
 
import { useEffect, useState } from "react";
 
function ClientData() {
  const [data, setData] = useState(null);
 
  useEffect(() => {
    fetch("/api/data")
      .then(res => res.json())
      .then(setData);
  }, []);
 
  return <div>{JSON.stringify(data)}</div>;
}

Use client fetching only when necessary.


Common Data Fetching Mistakes

Avoid these mistakes:

  • Using useEffect for server data unnecessarily
  • Fetching data in multiple places
  • Ignoring caching behavior
  • Exposing secrets to the client

Understanding where data should be fetched is critical.


Summary

In this lesson, you learned:

  • How data fetching differs in Next.js
  • Server Components and async pages
  • Basic fetch usage
  • Caching and revalidation
  • Client-side fetching scenarios
  • Common pitfalls

In the next lesson, we will explore SEO in Next.js and learn how to optimize pages for search engines.